Add Veles deployment IaC

This commit is contained in:
jenkins 2026-06-27 07:35:25 -03:00
parent 87e8146d5f
commit a1139cd3f6
17 changed files with 252 additions and 414 deletions

View File

@ -28,33 +28,3 @@ spec:
- veles-postgres - veles-postgres
retain: 8 retain: 8
concurrency: 1 concurrency: 1
---
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: veles-artifacts-backup
namespace: longhorn-system
spec:
name: veles-artifacts-backup
cron: "45 5 * * *"
task: backup
groups:
- veles
- veles-artifacts
retain: 7
concurrency: 1
---
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: veles-artifacts-snapshot
namespace: longhorn-system
spec:
name: veles-artifacts-snapshot
cron: "15 */6 * * *"
task: snapshot
groups:
- veles
- veles-artifacts
retain: 8
concurrency: 1

View File

@ -15,7 +15,6 @@ parameters:
fsType: ext4 fsType: ext4
replicaAutoBalance: disabled replicaAutoBalance: disabled
dataLocality: strict-local dataLocality: strict-local
recurringJobSelector: '[{"name":"veles-artifacts-backup","isGroup":false},{"name":"veles-artifacts-snapshot","isGroup":false}]'
reclaimPolicy: Retain reclaimPolicy: Retain
allowVolumeExpansion: true allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer volumeBindingMode: WaitForFirstConsumer

View File

@ -1,12 +1,13 @@
# services/keycloak/oneoffs/veles-gitea-oidc-secret-ensure-job.yaml # services/keycloak/oneoffs/veles-gitea-oidc-secret-ensure-job.yaml
# One-off job for sso/veles-gitea-oidc-secret-ensure-5. # One-off job for sso/veles-gitea-oidc-secret-ensure-1.
# Purpose: create/update the Veles realm Gitea OIDC client and write the # Purpose: create/update the Keycloak veles realm Gitea OIDC client, ensure the
# matching Gitea auth-source secret to Vault. # veles-tester group exists, and write the client secret to Vault for Gitea.
# Keep suspended until the Vault policy change has reconciled, then unsuspend once. # Run by setting spec.suspend to false, reconcile, then set it back to true.
# Safe to delete the finished Job/pod; it should not run continuously.
apiVersion: batch/v1 apiVersion: batch/v1
kind: Job kind: Job
metadata: metadata:
name: veles-gitea-oidc-secret-ensure-5 name: veles-gitea-oidc-secret-ensure-1
namespace: sso namespace: sso
spec: spec:
suspend: true suspend: true

View File

@ -1,11 +1,11 @@
# services/keycloak/oneoffs/veles-realm-ensure-job.yaml # services/keycloak/oneoffs/veles-realm-ensure-job.yaml
# One-off job for sso/veles-realm-ensure-4. # One-off job for sso/veles-realm-ensure-2.
# Purpose: create the Veles realm, groups, OIDC client, SMTP settings, and Vault client secret. # Purpose: create the Veles realm, groups, OIDC client, SMTP settings, and Vault client secret.
# Keep suspended until Veles Vault paths/policies have reconciled, then unsuspend once. # Keep suspended until Veles Vault paths/policies have reconciled, then unsuspend once.
apiVersion: batch/v1 apiVersion: batch/v1
kind: Job kind: Job
metadata: metadata:
name: veles-realm-ensure-4 name: veles-realm-ensure-2
namespace: sso namespace: sso
spec: spec:
suspend: true suspend: true
@ -157,7 +157,7 @@ spec:
create_payload = { create_payload = {
"realm": realm, "realm": realm,
"enabled": True, "enabled": True,
"registrationAllowed": True, "registrationAllowed": False,
"resetPasswordAllowed": True, "resetPasswordAllowed": True,
"verifyEmail": True, "verifyEmail": True,
"loginWithEmailAllowed": True, "loginWithEmailAllowed": True,
@ -174,7 +174,7 @@ spec:
realm_rep.update( realm_rep.update(
{ {
"enabled": True, "enabled": True,
"registrationAllowed": True, "registrationAllowed": False,
"resetPasswordAllowed": True, "resetPasswordAllowed": True,
"verifyEmail": True, "verifyEmail": True,
"loginWithEmailAllowed": True, "loginWithEmailAllowed": True,
@ -194,77 +194,14 @@ spec:
) )
if status != 200: if status != 200:
raise SystemExit(f"Group search failed for {name}: status={status}") raise SystemExit(f"Group search failed for {name}: status={status}")
for group in groups or []: if any(group.get("name") == name for group in groups or []):
if group.get("name") == name: return
return group["id"]
status, body = request("POST", f"{base_url}/admin/realms/{realm}/groups", token, {"name": name}) status, body = request("POST", f"{base_url}/admin/realms/{realm}/groups", token, {"name": name})
if status not in (201, 204, 409): if status not in (201, 204, 409):
raise SystemExit(f"Group create failed for {name}: status={status} body={body}") raise SystemExit(f"Group create failed for {name}: status={status} body={body}")
status, groups = request(
"GET",
f"{base_url}/admin/realms/{realm}/groups?search={urllib.parse.quote(name)}",
token,
)
if status != 200:
raise SystemExit(f"Group lookup failed after create for {name}: status={status}")
for group in groups or []:
if group.get("name") == name:
return group["id"]
raise SystemExit(f"Group {name} not found after create")
def ensure_role(name): ensure_group("alpha")
status, role = request("GET", f"{base_url}/admin/realms/{realm}/roles/{urllib.parse.quote(name)}", token) ensure_group("admin")
if status == 404:
status, body = request("POST", f"{base_url}/admin/realms/{realm}/roles", token, {"name": name})
if status not in (201, 204, 409):
raise SystemExit(f"Role create failed for {name}: status={status} body={body}")
status, role = request(
"GET",
f"{base_url}/admin/realms/{realm}/roles/{urllib.parse.quote(name)}",
token,
)
if status != 200 or not isinstance(role, dict):
raise SystemExit(f"Role lookup failed for {name}: status={status}")
return role
def ensure_group_role(group_id, role):
status, mappings = request(
"GET",
f"{base_url}/admin/realms/{realm}/groups/{group_id}/role-mappings/realm",
token,
)
if status != 200:
raise SystemExit(f"Group role mapping lookup failed: status={status}")
if any(mapping.get("name") == role["name"] for mapping in mappings or []):
return
status, body = request(
"POST",
f"{base_url}/admin/realms/{realm}/groups/{group_id}/role-mappings/realm",
token,
[role],
)
if status not in (200, 204):
raise SystemExit(f"Group role mapping failed for {role['name']}: status={status} body={body}")
def ensure_default_group(group_id, name):
status, groups = request("GET", f"{base_url}/admin/realms/{realm}/default-groups", token)
if status != 200:
raise SystemExit(f"Default group lookup failed: status={status}")
for group in groups or []:
if group.get("id") == group_id or group.get("name") == name:
return
status, body = request("PUT", f"{base_url}/admin/realms/{realm}/default-groups/{group_id}", token)
if status not in (200, 204):
raise SystemExit(f"Default group update failed for {name}: status={status} body={body}")
alpha_group_id = ensure_group("alpha")
admin_group_id = ensure_group("admin")
alpha_role = ensure_role("alpha")
admin_role = ensure_role("admin")
ensure_group_role(alpha_group_id, alpha_role)
ensure_group_role(admin_group_id, alpha_role)
ensure_group_role(admin_group_id, admin_role)
ensure_default_group(alpha_group_id, "alpha")
status, clients = request( status, clients = request(
"GET", "GET",
@ -336,7 +273,6 @@ spec:
raise SystemExit(f"Mapper lookup failed: status={status}") raise SystemExit(f"Mapper lookup failed: status={status}")
mapper_id = next((mapper.get("id") for mapper in mappers or [] if mapper.get("name") == "groups"), None) mapper_id = next((mapper.get("id") for mapper in mappers or [] if mapper.get("name") == "groups"), None)
if mapper_id: if mapper_id:
mapper_payload["id"] = mapper_id
status, body = request( status, body = request(
"PUT", "PUT",
f"{base_url}/admin/realms/{realm}/clients/{client_uuid}/protocol-mappers/models/{mapper_id}", f"{base_url}/admin/realms/{realm}/clients/{client_uuid}/protocol-mappers/models/{mapper_id}",

View File

@ -9,8 +9,7 @@ CLIENT_ID="${KEYCLOAK_CLIENT_ID:-gitea}"
PUBLIC_BASE_URL="${GITEA_PUBLIC_BASE_URL:-https://scm.bstein.dev}" PUBLIC_BASE_URL="${GITEA_PUBLIC_BASE_URL:-https://scm.bstein.dev}"
AUTH_SOURCE_NAME="${GITEA_AUTH_SOURCE_NAME:-veles}" AUTH_SOURCE_NAME="${GITEA_AUTH_SOURCE_NAME:-veles}"
TESTER_GROUP="${VELES_GITEA_TESTER_GROUP:-veles-tester}" TESTER_GROUP="${VELES_GITEA_TESTER_GROUP:-veles-tester}"
VAULT_SECRET_PATH="${VAULT_SECRET_PATH:-gitea/gitea-veles-oidc}" VAULT_SECRET_PATH="${VAULT_SECRET_PATH:-kv/data/atlas/gitea/gitea-veles-oidc}"
GROUP_TEAM_MAP="${GITEA_GROUP_TEAM_MAP:-{\"veles-tester\":{\"veles-alpha\":[\"testers\"]}}}"
ACCESS_TOKEN="" ACCESS_TOKEN=""
for attempt in 1 2 3 4 5 6 7 8 9 10; do for attempt in 1 2 3 4 5 6 7 8 9 10; do
@ -20,7 +19,6 @@ for attempt in 1 2 3 4 5 6 7 8 9 10; do
echo "Waiting for Keycloak to be reachable (attempt ${attempt})" >&2 echo "Waiting for Keycloak to be reachable (attempt ${attempt})" >&2
sleep $((attempt * 2)) sleep $((attempt * 2))
done done
for attempt in 1 2 3 4 5; do for attempt in 1 2 3 4 5; do
TOKEN_JSON="$(curl -sS -X POST "$KC_URL/realms/master/protocol/openid-connect/token" \ TOKEN_JSON="$(curl -sS -X POST "$KC_URL/realms/master/protocol/openid-connect/token" \
-H 'Content-Type: application/x-www-form-urlencoded' \ -H 'Content-Type: application/x-www-form-urlencoded' \
@ -44,198 +42,21 @@ ensure_group() {
group_name="$1" group_name="$1"
groups="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \ groups="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/groups?search=$(printf '%s' "${group_name}" | jq -sRr @uri)" || true)" "${KC_URL}/admin/realms/${REALM}/groups?search=$(printf '%s' "${group_name}" | jq -sRr @uri)" || true)"
group_id="$(echo "$groups" | jq -r --arg name "$group_name" '.[]? | select(.name == $name) | .id' | head -n1 || true)" if echo "$groups" | jq -e --arg name "$group_name" '.[]? | select(.name == $name)' >/dev/null 2>&1; then
if [ -n "$group_id" ] && [ "$group_id" != "null" ]; then
printf '%s' "$group_id"
return return
fi fi
status="$(curl -sS -o /tmp/keycloak-group-create.json -w "%{http_code}" -X POST \ status="$(curl -sS -o /dev/null -w "%{http_code}" -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d "$(jq -nc --arg name "$group_name" '{name:$name}')" \ -d "$(jq -nc --arg name "$group_name" '{name:$name}')" \
"${KC_URL}/admin/realms/${REALM}/groups")" "${KC_URL}/admin/realms/${REALM}/groups")"
if [ "$status" != "201" ] && [ "$status" != "204" ] && [ "$status" != "409" ]; then if [ "$status" != "201" ] && [ "$status" != "204" ] && [ "$status" != "409" ]; then
echo "Keycloak group create failed for ${group_name} (status ${status})" >&2 echo "Keycloak group create failed for ${group_name} (status ${status})" >&2
cat /tmp/keycloak-group-create.json >&2 || true
exit 1
fi
groups="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/groups?search=$(printf '%s' "${group_name}" | jq -sRr @uri)" || true)"
group_id="$(echo "$groups" | jq -r --arg name "$group_name" '.[]? | select(.name == $name) | .id' | head -n1 || true)"
if [ -z "$group_id" ] || [ "$group_id" = "null" ]; then
echo "Keycloak group ${group_name} not found after create" >&2
exit 1
fi
printf '%s' "$group_id"
}
ensure_role() {
role_name="$1"
role="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/roles/$(printf '%s' "${role_name}" | jq -sRr @uri)" || true)"
if echo "$role" | jq -e --arg name "$role_name" '.name == $name' >/dev/null 2>&1; then
printf '%s' "$role"
return
fi
status="$(curl -sS -o /tmp/keycloak-role-create.json -w "%{http_code}" -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d "$(jq -nc --arg name "$role_name" '{name:$name}')" \
"${KC_URL}/admin/realms/${REALM}/roles")"
if [ "$status" != "201" ] && [ "$status" != "204" ] && [ "$status" != "409" ]; then
echo "Keycloak role create failed for ${role_name} (status ${status})" >&2
cat /tmp/keycloak-role-create.json >&2 || true
exit 1
fi
role="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/roles/$(printf '%s' "${role_name}" | jq -sRr @uri)" || true)"
if ! echo "$role" | jq -e --arg name "$role_name" '.name == $name' >/dev/null 2>&1; then
echo "Keycloak role ${role_name} not found after create" >&2
exit 1
fi
printf '%s' "$role"
}
ensure_group_role() {
group_id="$1"
role_json="$2"
role_name="$(echo "$role_json" | jq -r '.name')"
mappings="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/groups/${group_id}/role-mappings/realm" || true)"
if echo "$mappings" | jq -e --arg name "$role_name" '.[]? | select(.name == $name)' >/dev/null 2>&1; then
return
fi
status="$(curl -sS -o /tmp/keycloak-group-role.json -w "%{http_code}" -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d "[$role_json]" \
"${KC_URL}/admin/realms/${REALM}/groups/${group_id}/role-mappings/realm")"
if [ "$status" != "200" ] && [ "$status" != "204" ]; then
echo "Keycloak group role mapping failed for ${role_name} (status ${status})" >&2
cat /tmp/keycloak-group-role.json >&2 || true
exit 1 exit 1
fi fi
} }
ensure_mapper() { ensure_group "${TESTER_GROUP}"
client_uuid="$1"
mapper_name="$2"
mapper_payload="$3"
mappers="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/clients/${client_uuid}/protocol-mappers/models" || true)"
mapper_id="$(echo "$mappers" | jq -r --arg name "$mapper_name" '.[]? | select(.name == $name) | .id' | head -n1 || true)"
if [ -n "$mapper_id" ] && [ "$mapper_id" != "null" ]; then
mapper_payload="$(echo "$mapper_payload" | jq --arg id "$mapper_id" '. + {id:$id}')"
status="$(curl -sS -o /tmp/keycloak-mapper.json -w "%{http_code}" -X PUT \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d "${mapper_payload}" \
"${KC_URL}/admin/realms/${REALM}/clients/${client_uuid}/protocol-mappers/models/${mapper_id}")"
else
status="$(curl -sS -o /tmp/keycloak-mapper.json -w "%{http_code}" -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d "${mapper_payload}" \
"${KC_URL}/admin/realms/${REALM}/clients/${client_uuid}/protocol-mappers/models")"
fi
if [ "$status" != "200" ] && [ "$status" != "201" ] && [ "$status" != "204" ]; then
echo "Keycloak mapper ensure failed for ${mapper_name} (status ${status})" >&2
cat /tmp/keycloak-mapper.json >&2 || true
exit 1
fi
}
ensure_client_scope() {
scope_name="$1"
scopes="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/client-scopes?search=$(printf '%s' "${scope_name}" | jq -sRr @uri)" || true)"
scope_id="$(echo "$scopes" | jq -r --arg name "$scope_name" '.[]? | select(.name == $name) | .id' | head -n1 || true)"
if [ -n "$scope_id" ] && [ "$scope_id" != "null" ]; then
printf '%s' "$scope_id"
return
fi
scope_payload="$(jq -nc --arg name "$scope_name" '{name:$name,protocol:"openid-connect",attributes:{"include.in.token.scope":"true","display.on.consent.screen":"false"}}')"
status="$(curl -sS -o /tmp/keycloak-client-scope-create.json -w "%{http_code}" -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d "${scope_payload}" \
"${KC_URL}/admin/realms/${REALM}/client-scopes")"
if [ "$status" != "201" ] && [ "$status" != "204" ] && [ "$status" != "409" ]; then
echo "Keycloak client scope create failed for ${scope_name} (status ${status})" >&2
cat /tmp/keycloak-client-scope-create.json >&2 || true
exit 1
fi
scopes="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/client-scopes?search=$(printf '%s' "${scope_name}" | jq -sRr @uri)" || true)"
scope_id="$(echo "$scopes" | jq -r --arg name "$scope_name" '.[]? | select(.name == $name) | .id' | head -n1 || true)"
if [ -z "$scope_id" ] || [ "$scope_id" = "null" ]; then
echo "Keycloak client scope ${scope_name} not found after create" >&2
exit 1
fi
printf '%s' "$scope_id"
}
ensure_scope_mapper() {
scope_id="$1"
mapper_name="$2"
mapper_payload="$3"
mappers="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/client-scopes/${scope_id}/protocol-mappers/models" || true)"
mapper_id="$(echo "$mappers" | jq -r --arg name "$mapper_name" '.[]? | select(.name == $name) | .id' | head -n1 || true)"
if [ -n "$mapper_id" ] && [ "$mapper_id" != "null" ]; then
mapper_payload="$(echo "$mapper_payload" | jq --arg id "$mapper_id" '. + {id:$id}')"
status="$(curl -sS -o /tmp/keycloak-scope-mapper.json -w "%{http_code}" -X PUT \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d "${mapper_payload}" \
"${KC_URL}/admin/realms/${REALM}/client-scopes/${scope_id}/protocol-mappers/models/${mapper_id}")"
else
status="$(curl -sS -o /tmp/keycloak-scope-mapper.json -w "%{http_code}" -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d "${mapper_payload}" \
"${KC_URL}/admin/realms/${REALM}/client-scopes/${scope_id}/protocol-mappers/models")"
fi
if [ "$status" != "200" ] && [ "$status" != "201" ] && [ "$status" != "204" ]; then
echo "Keycloak client-scope mapper ensure failed for ${mapper_name} (status ${status})" >&2
cat /tmp/keycloak-scope-mapper.json >&2 || true
exit 1
fi
}
ensure_client_optional_scope() {
client_uuid="$1"
scope_id="$2"
scope_name="$3"
default_scopes="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/clients/${client_uuid}/default-client-scopes" || true)"
optional_scopes="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/clients/${client_uuid}/optional-client-scopes" || true)"
if echo "$default_scopes" | jq -e --arg name "$scope_name" '.[]? | select(.name == $name)' >/dev/null 2>&1 \
|| echo "$optional_scopes" | jq -e --arg name "$scope_name" '.[]? | select(.name == $name)' >/dev/null 2>&1; then
return
fi
status="$(curl -sS -o /dev/null -w "%{http_code}" -X PUT \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/clients/${client_uuid}/optional-client-scopes/${scope_id}")"
if [ "$status" != "200" ] && [ "$status" != "201" ] && [ "$status" != "204" ]; then
status="$(curl -sS -o /dev/null -w "%{http_code}" -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/clients/${client_uuid}/optional-client-scopes/${scope_id}")"
if [ "$status" != "200" ] && [ "$status" != "201" ] && [ "$status" != "204" ]; then
echo "Failed to attach ${scope_name} client scope to ${CLIENT_ID} (status ${status})" >&2
exit 1
fi
fi
}
TESTER_GROUP_ID="$(ensure_group "${TESTER_GROUP}")"
TESTER_ROLE="$(ensure_role "${TESTER_GROUP}")"
ensure_group_role "${TESTER_GROUP_ID}" "${TESTER_ROLE}"
CLIENT_QUERY="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \ CLIENT_QUERY="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/clients?clientId=$(printf '%s' "${CLIENT_ID}" | jq -sRr @uri)" || true)" "${KC_URL}/admin/realms/${REALM}/clients?clientId=$(printf '%s' "${CLIENT_ID}" | jq -sRr @uri)" || true)"
@ -245,17 +66,16 @@ client_payload="$(jq -nc \
--arg client_id "${CLIENT_ID}" \ --arg client_id "${CLIENT_ID}" \
--arg root_url "${PUBLIC_BASE_URL}" \ --arg root_url "${PUBLIC_BASE_URL}" \
--arg callback "${PUBLIC_BASE_URL}/user/oauth2/${AUTH_SOURCE_NAME}/callback" \ --arg callback "${PUBLIC_BASE_URL}/user/oauth2/${AUTH_SOURCE_NAME}/callback" \
'{clientId:$client_id,enabled:true,protocol:"openid-connect",publicClient:false,standardFlowEnabled:true,implicitFlowEnabled:false,directAccessGrantsEnabled:false,serviceAccountsEnabled:false,redirectUris:[$callback],webOrigins:[$root_url],rootUrl:$root_url,baseUrl:"/",attributes:{"pkce.code.challenge.method":"","post.logout.redirect.uris":($root_url + "/*")}}')" '{clientId:$client_id,enabled:true,protocol:"openid-connect",publicClient:false,standardFlowEnabled:true,implicitFlowEnabled:false,directAccessGrantsEnabled:false,serviceAccountsEnabled:false,redirectUris:[$callback],webOrigins:[$root_url],rootUrl:$root_url,baseUrl:"/",attributes:{"pkce.code.challenge.method":"S256","post.logout.redirect.uris":($root_url + "/*")}}')"
if [ -z "$CLIENT_UUID" ] || [ "$CLIENT_UUID" = "null" ]; then if [ -z "$CLIENT_UUID" ] || [ "$CLIENT_UUID" = "null" ]; then
status="$(curl -sS -o /tmp/keycloak-client-create.json -w "%{http_code}" -X POST \ status="$(curl -sS -o /dev/null -w "%{http_code}" -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d "${client_payload}" \ -d "${client_payload}" \
"${KC_URL}/admin/realms/${REALM}/clients")" "${KC_URL}/admin/realms/${REALM}/clients")"
if [ "$status" != "201" ] && [ "$status" != "204" ] && [ "$status" != "409" ]; then if [ "$status" != "201" ] && [ "$status" != "204" ] && [ "$status" != "409" ]; then
echo "Keycloak client create failed for ${CLIENT_ID} (status ${status})" >&2 echo "Keycloak client create failed for ${CLIENT_ID} (status ${status})" >&2
cat /tmp/keycloak-client-create.json >&2 || true
exit 1 exit 1
fi fi
CLIENT_QUERY="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \ CLIENT_QUERY="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
@ -268,26 +88,38 @@ if [ -z "$CLIENT_UUID" ] || [ "$CLIENT_UUID" = "null" ]; then
exit 1 exit 1
fi fi
status="$(curl -sS -o /tmp/keycloak-client-update.json -w "%{http_code}" -X PUT \ status="$(curl -sS -o /dev/null -w "%{http_code}" -X PUT \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d "${client_payload}" \ -d "${client_payload}" \
"${KC_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}")" "${KC_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}")"
if [ "$status" != "200" ] && [ "$status" != "204" ]; then if [ "$status" != "200" ] && [ "$status" != "204" ]; then
echo "Keycloak client update failed for ${CLIENT_ID} (status ${status})" >&2 echo "Keycloak client update failed for ${CLIENT_ID} (status ${status})" >&2
cat /tmp/keycloak-client-update.json >&2 || true
exit 1 exit 1
fi fi
groups_mapper_payload="$(jq -nc \ mapper_payload="$(jq -nc \
'{name:"groups",protocol:"openid-connect",protocolMapper:"oidc-group-membership-mapper",consentRequired:false,config:{"full.path":"false","id.token.claim":"true","access.token.claim":"true","userinfo.token.claim":"true","claim.name":"groups","jsonType.label":"String"}}')" '{name:"groups",protocol:"openid-connect",protocolMapper:"oidc-group-membership-mapper",consentRequired:false,config:{"full.path":"false","id.token.claim":"true","access.token.claim":"true","userinfo.token.claim":"true","claim.name":"groups","jsonType.label":"String"}}')"
roles_mapper_payload="$(jq -nc \ mappers="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
'{name:"roles",protocol:"openid-connect",protocolMapper:"oidc-usermodel-realm-role-mapper",consentRequired:false,config:{"multivalued":"true","id.token.claim":"true","access.token.claim":"true","userinfo.token.claim":"true","claim.name":"roles","jsonType.label":"String"}}')" "${KC_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}/protocol-mappers/models" || true)"
ensure_mapper "${CLIENT_UUID}" groups "${groups_mapper_payload}" MAPPER_ID="$(echo "$mappers" | jq -r '.[]? | select(.name == "groups") | .id' | head -n1 || true)"
ensure_mapper "${CLIENT_UUID}" roles "${roles_mapper_payload}" if [ -n "$MAPPER_ID" ] && [ "$MAPPER_ID" != "null" ]; then
GROUPS_SCOPE_ID="$(ensure_client_scope groups)" status="$(curl -sS -o /dev/null -w "%{http_code}" -X PUT \
ensure_scope_mapper "${GROUPS_SCOPE_ID}" groups "${groups_mapper_payload}" -H "Authorization: Bearer ${ACCESS_TOKEN}" \
ensure_client_optional_scope "${CLIENT_UUID}" "${GROUPS_SCOPE_ID}" groups -H 'Content-Type: application/json' \
-d "${mapper_payload}" \
"${KC_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}/protocol-mappers/models/${MAPPER_ID}")"
else
status="$(curl -sS -o /dev/null -w "%{http_code}" -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d "${mapper_payload}" \
"${KC_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}/protocol-mappers/models")"
fi
if [ "$status" != "200" ] && [ "$status" != "201" ] && [ "$status" != "204" ]; then
echo "Keycloak groups mapper ensure failed (status ${status})" >&2
exit 1
fi
CLIENT_SECRET="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \ CLIENT_SECRET="$(curl -sS -H "Authorization: Bearer ${ACCESS_TOKEN}" \
"${KC_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}/client-secret" | jq -r '.value' 2>/dev/null || true)" "${KC_URL}/admin/realms/${REALM}/clients/${CLIENT_UUID}/client-secret" | jq -r '.value' 2>/dev/null || true)"
@ -310,21 +142,16 @@ fi
payload="$(jq -nc \ payload="$(jq -nc \
--arg client_id "${CLIENT_ID}" \ --arg client_id "${CLIENT_ID}" \
--arg client_secret "${CLIENT_SECRET}" \ --arg client_secret "${CLIENT_SECRET}" \
--arg discovery_url "${PUBLIC_BASE_URL}" \
--arg issuer "https://sso.bstein.dev/realms/${REALM}" \ --arg issuer "https://sso.bstein.dev/realms/${REALM}" \
--arg auto_discovery_url "https://sso.bstein.dev/realms/${REALM}/.well-known/openid-configuration" \ --arg auto_discovery_url "https://sso.bstein.dev/realms/${REALM}/.well-known/openid-configuration" \
--arg auth_source_name "${AUTH_SOURCE_NAME}" \ --arg auth_source_name "${AUTH_SOURCE_NAME}" \
--arg tester_group "${TESTER_GROUP}" \ --arg tester_group "${TESTER_GROUP}" \
--arg group_team_map "${GROUP_TEAM_MAP}" \ --arg group_team_map "{\"${TESTER_GROUP}\":{\"veles-alpha\":[\"testers\"]}}" \
'{data:{client_id:$client_id,client_secret:$client_secret,issuer:$issuer,openid_auto_discovery_url:$auto_discovery_url,auth_source_name:$auth_source_name,required_claim_name:"groups",required_claim_value:$tester_group,group_claim_name:"groups",restricted_group:$tester_group,group_team_map:$group_team_map}}')" '{data:{client_id:$client_id,client_secret:$client_secret,issuer:$issuer,openid_auto_discovery_url:$auto_discovery_url,auth_source_name:$auth_source_name,required_claim_name:"groups",required_claim_value:$tester_group,group_claim_name:"groups",restricted_group:$tester_group,group_team_map:$group_team_map,gitea_base_url:$discovery_url}}')"
write_status="$(curl -sS -o /tmp/veles-gitea-oidc-write.json -w "%{http_code}" -X POST \ curl -sS -X POST -H "X-Vault-Token: ${vault_token}" \
-H "X-Vault-Token: ${vault_token}" \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d "${payload}" "${vault_addr}/v1/kv/data/atlas/${VAULT_SECRET_PATH}")" -d "${payload}" "${vault_addr}/v1/${VAULT_SECRET_PATH}" >/dev/null
if [ "${write_status}" != "200" ] && [ "${write_status}" != "204" ]; then
echo "Vault write failed for ${VAULT_SECRET_PATH} (status ${write_status})" >&2
cat /tmp/veles-gitea-oidc-write.json >&2 || true
exit 1
fi
echo "Veles Gitea OIDC client ready in Keycloak and Vault" echo "Veles realm Gitea OIDC client ready"

View File

@ -7,11 +7,26 @@ metadata:
labels: labels:
app.kubernetes.io/name: veles app.kubernetes.io/name: veles
app.kubernetes.io/component: artifacts app.kubernetes.io/component: artifacts
veles.bstein.dev/backup: longhorn
spec: spec:
accessModes: accessModes:
- ReadWriteOnce - ReadWriteOnce
storageClassName: veles-oceanus-artifacts storageClassName: veles-oceanus-artifacts
resources: resources:
requests: requests:
storage: 200Gi storage: 500Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: veles-engine-cache
namespace: veles
labels:
app.kubernetes.io/name: veles
app.kubernetes.io/component: engine-cache
spec:
accessModes:
- ReadWriteOnce
storageClassName: veles-oceanus-artifacts
resources:
requests:
storage: 100Gi

View File

@ -16,11 +16,30 @@ spec:
metadata: metadata:
labels: labels:
app: veles-backend app: veles-backend
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-pre-populate-only: "true"
vault.hashicorp.com/role: "veles"
vault.hashicorp.com/agent-inject-secret-veles-env.sh: "kv/data/atlas/veles/veles-db"
vault.hashicorp.com/agent-inject-template-veles-env.sh: |
{{- with secret "kv/data/atlas/veles/veles-db" }}
export DATABASE_URL="{{ .Data.data.DATABASE_URL }}"
export VELES_DATABASE_USER="{{ .Data.data.POSTGRES_USER }}"
export VELES_DATABASE_PASSWORD="{{ .Data.data.POSTGRES_PASSWORD }}"
{{- end }}
{{- with secret "kv/data/atlas/veles/veles-oidc" }}
export VELES_OIDC_CLIENT_SECRET="{{ .Data.data.client_secret }}"
{{- end }}
{{- with secret "kv/data/atlas/veles/app-secrets" }}
export VELES_SESSION_SECRET="{{ .Data.data.VELES_SESSION_SECRET }}"
export VELES_BYOK_ENCRYPTION_KEY="{{ .Data.data.VELES_BYOK_ENCRYPTION_KEY }}"
{{- end }}
spec: spec:
serviceAccountName: veles-backend serviceAccountName: veles-backend
priorityClassName: veles-core priorityClassName: veles-core
nodeSelector: nodeSelector:
veles.bstein.dev/node-pool: oceanus veles.bstein.dev/node-pool: oceanus
kubernetes.io/arch: amd64
tolerations: tolerations:
- key: veles.bstein.dev/simulation - key: veles.bstein.dev/simulation
operator: Equal operator: Equal
@ -32,41 +51,46 @@ spec:
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
initContainers: initContainers:
- name: migrate-db - name: database-init
image: registry.bstein.dev/veles/veles-backend:0.3.15 # {"$imagepolicy": "veles:veles-backend"} image: registry.bstein.dev/veles/veles-backend:0.3.16 # {"$imagepolicy": "veles:veles-backend"}
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
command: ["veles-db"] command: ["/bin/sh", "-c"]
args: ["--init", "--json"] args:
- |
set -eu
if [ -f /vault/secrets/veles-env.sh ]; then
. /vault/secrets/veles-env.sh
fi
exec veles-db --init --wait-seconds 120 --bootstrap-meta --content-root /opt/veles-content
envFrom: envFrom:
- configMapRef: - configMapRef:
name: veles-app-config name: veles-config
- secretRef:
name: veles-runtime-secrets
resources: resources:
requests: requests:
cpu: 100m cpu: 50m
memory: 256Mi memory: 128Mi
limits: limits:
cpu: 500m cpu: 250m
memory: 512Mi memory: 512Mi
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
containers: containers:
- name: backend - name: backend
image: registry.bstein.dev/veles/veles-backend:0.3.15 # {"$imagepolicy": "veles:veles-backend"} image: registry.bstein.dev/veles/veles-backend:0.3.16 # {"$imagepolicy": "veles:veles-backend"}
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
env: command: ["/bin/sh", "-c"]
- name: VELES_SIM_IMAGE args:
value: registry.bstein.dev/veles/veles-sim-worker:0.3.15 # {"$imagepolicy": "veles:veles-sim-worker"} - |
set -eu
if [ -f /vault/secrets/veles-env.sh ]; then
. /vault/secrets/veles-env.sh
fi
exec veles-web --host 0.0.0.0 --port 8796 --no-resume-queued
ports: ports:
- name: http - name: http
containerPort: 8796 containerPort: 8796
protocol: TCP protocol: TCP
envFrom:
- configMapRef:
name: veles-config
readinessProbe: readinessProbe:
httpGet: httpGet:
path: /api/v1/ready path: /api/v1/ready
@ -79,18 +103,13 @@ spec:
port: http port: http
initialDelaySeconds: 20 initialDelaySeconds: 20
periodSeconds: 20 periodSeconds: 20
envFrom:
- configMapRef:
name: veles-app-config
- secretRef:
name: veles-runtime-secrets
resources: resources:
requests: requests:
cpu: 250m cpu: 250m
memory: 512Mi memory: 512Mi
limits: limits:
cpu: "1" cpu: "1"
memory: 2Gi memory: 1Gi
securityContext: securityContext:
runAsNonRoot: true runAsNonRoot: true
runAsUser: 10001 runAsUser: 10001

View File

@ -2,55 +2,44 @@
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: veles-app-config name: veles-config
namespace: veles namespace: veles
data: data:
VELES_ENV: alpha
VELES_PROFILE: cluster VELES_PROFILE: cluster
VELES_AUTH_MODE: oidc VELES_AUTH_MODE: oidc
VELES_SIM_RUNNER: kubernetes-job VELES_SIM_RUNNER: kubernetes-job
VELES_PUBLIC_URL: https://veles.bstein.dev VELES_PUBLIC_URL: https://veles.bstein.dev
VELES_PUBLIC_BASE_URL: https://veles.bstein.dev VELES_PUBLIC_BASE_URL: https://veles.bstein.dev
VELES_BACKEND_HTTP_PORT: "8796" VELES_ALPHA_LABEL: ALPHA
VELES_FRONTEND_HTTP_PORT: "8080"
VELES_OIDC_ISSUER_URL: https://sso.bstein.dev/realms/veles VELES_OIDC_ISSUER_URL: https://sso.bstein.dev/realms/veles
VELES_OIDC_ISSUER: https://sso.bstein.dev/realms/veles VELES_OIDC_ISSUER: https://sso.bstein.dev/realms/veles
VELES_OIDC_CLIENT_ID: veles-web VELES_OIDC_CLIENT_ID: veles-web
VELES_OIDC_ALLOWED_GROUPS: alpha,admin VELES_OIDC_ALLOWED_GROUPS: alpha,veles-tester,admin
VELES_OIDC_REQUIRED_GROUPS: alpha,admin VELES_OIDC_REQUIRED_GROUPS: alpha,veles-tester,admin
VELES_OIDC_ADMIN_GROUPS: admin VELES_OIDC_ADMIN_GROUPS: admin
VELES_OIDC_GROUPS_CLAIM: groups
VELES_OIDC_ROLES_CLAIM: realm_access.roles
VELES_DATABASE_HOST: veles-postgres.veles.svc.cluster.local
VELES_DATABASE_PORT: "5432"
VELES_DATABASE_NAME: veles
VELES_ARTIFACTS_PATH: /data/veles-artifacts
VELES_ARTIFACTS_MODE: rwo-backend-owned
VELES_LOG_ROOT: /data/veles-artifacts/logs
VELES_REPORT_ROOT: /data/veles-artifacts/reports
VELES_ARTIFACT_ROOT: /data/veles-artifacts/artifacts
VELES_RETENTION_DAYS: "30"
VELES_SIM_NAMESPACE: veles
VELES_NAMESPACE: veles VELES_NAMESPACE: veles
VELES_SIM_IMAGE: registry.bstein.dev/veles/veles-sim-worker:0.3.15 # {"$imagepolicy": "veles:veles-sim-worker"} VELES_SIM_IMAGE: registry.bstein.dev/veles/veles-sim-worker:0.3.16 # {"$imagepolicy": "veles:veles-sim-worker"}
VELES_SIM_SERVICE_ACCOUNT: veles-sim VELES_SIM_SERVICE_ACCOUNT: veles-sim
VELES_SIM_PRIORITY_CLASS: veles-sim VELES_SIM_PRIORITY_CLASS: veles-sim
VELES_SIM_NODE_SELECTOR: veles.bstein.dev/node-pool=oceanus,kubernetes.io/arch=amd64 VELES_SIM_NODE_SELECTOR: veles.bstein.dev/node-pool=oceanus,kubernetes.io/arch=amd64
VELES_SIM_TOLERATIONS: veles.bstein.dev/simulation=true:NoSchedule VELES_SIM_TOLERATIONS: veles.bstein.dev/simulation=true:NoSchedule
VELES_SIM_TOLERATION_KEY: veles.bstein.dev/simulation
VELES_SIM_TOLERATION_VALUE: "true"
VELES_SIM_ACTIVE_DEADLINE_SECONDS: "7200" VELES_SIM_ACTIVE_DEADLINE_SECONDS: "7200"
VELES_SIM_TTL_SECONDS: "3600" VELES_SIM_TTL_SECONDS: "3600"
VELES_SIM_CPU_REQUEST: 500m VELES_SIM_CPU_REQUEST: 500m
VELES_SIM_CPU_LIMIT: "2" VELES_SIM_CPU_LIMIT: "2"
VELES_SIM_MEMORY_REQUEST: 1Gi VELES_SIM_MEMORY_REQUEST: 1Gi
VELES_SIM_MEMORY_LIMIT: 4Gi VELES_SIM_MEMORY_LIMIT: 4Gi
VELES_SIM_ARTIFACT_PVC: veles-artifacts
VELES_SIM_ARTIFACT_MOUNT_PATH: /data/veles-artifacts
VELES_SIM_FS_GROUP: "10001" VELES_SIM_FS_GROUP: "10001"
VELES_MAX_ACTIVE_SIMS_PER_USER: "1" VELES_MAX_ACTIVE_SIMS_PER_USER: "1"
VELES_MAX_ACTIVE_SIMS_GLOBAL: "4" VELES_MAX_ACTIVE_SIMS_GLOBAL: "4"
VELES_RETENTION_NODE_SELECTOR: veles.bstein.dev/simulation=true VELES_RETENTION_DAYS: "30"
VELES_RETENTION_TOLERATION_KEY: veles.bstein.dev/simulation VELES_LOG_ROOT: /data/veles-artifacts/logs
VELES_RETENTION_TOLERATION_VALUE: "true" VELES_REPORT_ROOT: /data/veles-artifacts/reports
VELES_LOG_RETENTION_DAYS: "30" VELES_ARTIFACT_ROOT: /data/veles-artifacts/artifacts
VELES_SIM_ARTIFACT_PVC: veles-artifacts
VELES_SIM_ARTIFACT_MOUNT_PATH: /data/veles-artifacts
VELES_SIM_ENGINE_PVC: veles-engine-cache
VELES_SIM_ENGINE_MOUNT_PATH: /engine
VELES_SIM_CODEX_CLI_SECRET_PROVIDER_CLASS: veles-codex-cli
VELES_SIM_CODEX_CLI_MOUNT_PATH: /home/veles/.codex
VELES_SIM_CODEX_CLI_HOME: /home/veles/.codex

View File

@ -19,6 +19,7 @@ spec:
spec: spec:
serviceAccountName: veles-frontend serviceAccountName: veles-frontend
priorityClassName: veles-core priorityClassName: veles-core
automountServiceAccountToken: false
affinity: affinity:
nodeAffinity: nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: requiredDuringSchedulingIgnoredDuringExecution:
@ -43,12 +44,11 @@ spec:
values: ["rpi5"] values: ["rpi5"]
securityContext: securityContext:
fsGroup: 101 fsGroup: 101
fsGroupChangePolicy: OnRootMismatch
seccompProfile: seccompProfile:
type: RuntimeDefault type: RuntimeDefault
containers: containers:
- name: frontend - name: frontend
image: registry.bstein.dev/veles/veles-frontend:0.3.15 # {"$imagepolicy": "veles:veles-frontend"} image: registry.bstein.dev/veles/veles-frontend:0.3.16 # {"$imagepolicy": "veles:veles-frontend"}
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- name: http - name: http
@ -66,20 +66,15 @@ spec:
port: http port: http
initialDelaySeconds: 20 initialDelaySeconds: 20
periodSeconds: 20 periodSeconds: 20
envFrom:
- configMapRef:
name: veles-app-config
resources: resources:
requests: requests:
cpu: 100m cpu: 50m
memory: 256Mi memory: 64Mi
limits: limits:
cpu: 500m cpu: 250m
memory: 512Mi memory: 256Mi
securityContext: securityContext:
runAsNonRoot: true runAsNonRoot: true
runAsUser: 101
runAsGroup: 101
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
capabilities: capabilities:
drop: ["ALL"] drop: ["ALL"]

View File

@ -18,12 +18,9 @@ metadata:
spec: spec:
imageRepositoryRef: imageRepositoryRef:
name: veles-backend name: veles-backend
filterTags:
pattern: '^(?P<version>\d+\.\d+\.\d+)$'
extract: '$version'
policy: policy:
semver: semver:
range: ">=0.1.0" range: ">=0.1.0-0"
--- ---
apiVersion: image.toolkit.fluxcd.io/v1 apiVersion: image.toolkit.fluxcd.io/v1
kind: ImageRepository kind: ImageRepository
@ -44,12 +41,9 @@ metadata:
spec: spec:
imageRepositoryRef: imageRepositoryRef:
name: veles-frontend name: veles-frontend
filterTags:
pattern: '^(?P<version>\d+\.\d+\.\d+)$'
extract: '$version'
policy: policy:
semver: semver:
range: ">=0.1.0" range: ">=0.1.0-0"
--- ---
apiVersion: image.toolkit.fluxcd.io/v1 apiVersion: image.toolkit.fluxcd.io/v1
kind: ImageRepository kind: ImageRepository
@ -70,9 +64,6 @@ metadata:
spec: spec:
imageRepositoryRef: imageRepositoryRef:
name: veles-sim-worker name: veles-sim-worker
filterTags:
pattern: '^(?P<version>\d+\.\d+\.\d+)$'
extract: '$version'
policy: policy:
semver: semver:
range: ">=0.1.0" range: ">=0.1.0-0"

View File

@ -17,6 +17,7 @@ resources:
- services.yaml - services.yaml
- backend-deployment.yaml - backend-deployment.yaml
- frontend-deployment.yaml - frontend-deployment.yaml
- retention-cronjob.yaml
- image.yaml - image.yaml
- ingress.yaml - ingress.yaml
- oneoffs/veles-secrets-ensure-job.yaml - oneoffs/veles-secrets-ensure-job.yaml

View File

@ -46,7 +46,7 @@ spec:
type: RuntimeDefault type: RuntimeDefault
containers: containers:
- name: postgres - name: postgres
image: postgres:15 image: postgres:17
ports: ports:
- name: postgres - name: postgres
containerPort: 5432 containerPort: 5432
@ -62,13 +62,15 @@ spec:
value: veles value: veles
resources: resources:
requests: requests:
cpu: "2" cpu: "1"
memory: 8Gi memory: 2Gi
limits: limits:
cpu: "4" cpu: "4"
memory: 16Gi memory: 8Gi
securityContext: securityContext:
allowPrivilegeEscalation: false allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
volumeMounts: volumeMounts:
- name: postgres-data - name: postgres-data
mountPath: /var/lib/postgresql/data mountPath: /var/lib/postgresql/data
@ -83,4 +85,4 @@ spec:
storageClassName: veles-oceanus-db storageClassName: veles-oceanus-db
resources: resources:
requests: requests:
storage: 100Gi storage: 200Gi

View File

@ -13,7 +13,7 @@ spec:
pods: "60" pods: "60"
count/jobs.batch: "100" count/jobs.batch: "100"
persistentvolumeclaims: "8" persistentvolumeclaims: "8"
requests.storage: 300Gi requests.storage: 1Ti
--- ---
apiVersion: v1 apiVersion: v1
kind: ResourceQuota kind: ResourceQuota

View File

@ -0,0 +1,67 @@
# services/veles/retention-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: veles-retention
namespace: veles
labels:
app: veles-retention
spec:
schedule: "17 4 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
metadata:
labels:
app: veles-retention
spec:
restartPolicy: Never
serviceAccountName: veles-retention
automountServiceAccountToken: false
priorityClassName: veles-core
nodeSelector:
veles.bstein.dev/node-pool: oceanus
kubernetes.io/arch: amd64
tolerations:
- key: veles.bstein.dev/simulation
operator: Equal
value: "true"
effect: NoSchedule
securityContext:
fsGroup: 10001
fsGroupChangePolicy: OnRootMismatch
seccompProfile:
type: RuntimeDefault
containers:
- name: retention
image: registry.bstein.dev/veles/veles-backend:0.3.16 # {"$imagepolicy": "veles:veles-backend"}
imagePullPolicy: IfNotPresent
command: ["veles-hygiene"]
args: ["--prune-artifacts"]
envFrom:
- configMapRef:
name: veles-config
volumeMounts:
- name: artifacts
mountPath: /data/veles-artifacts
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 250m
memory: 512Mi
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
volumes:
- name: artifacts
persistentVolumeClaim:
claimName: veles-artifacts

View File

@ -13,22 +13,22 @@ spec:
- objectName: "harbor-pull__dockerconfigjson" - objectName: "harbor-pull__dockerconfigjson"
secretPath: "kv/data/atlas/shared/harbor-pull" secretPath: "kv/data/atlas/shared/harbor-pull"
secretKey: "dockerconfigjson" secretKey: "dockerconfigjson"
- objectName: "veles-db__DATABASE_URL" - objectName: "veles-db__database-url"
secretPath: "kv/data/atlas/veles/veles-db" secretPath: "kv/data/atlas/veles/veles-db"
secretKey: "DATABASE_URL" secretKey: "DATABASE_URL"
- objectName: "veles-db__POSTGRES_USER" - objectName: "veles-db__user"
secretPath: "kv/data/atlas/veles/veles-db" secretPath: "kv/data/atlas/veles/veles-db"
secretKey: "POSTGRES_USER" secretKey: "POSTGRES_USER"
- objectName: "veles-db__POSTGRES_PASSWORD" - objectName: "veles-db__password"
secretPath: "kv/data/atlas/veles/veles-db" secretPath: "kv/data/atlas/veles/veles-db"
secretKey: "POSTGRES_PASSWORD" secretKey: "POSTGRES_PASSWORD"
- objectName: "veles-oidc__client_secret" - objectName: "veles-oidc__client-secret"
secretPath: "kv/data/atlas/veles/veles-oidc" secretPath: "kv/data/atlas/veles/veles-oidc"
secretKey: "client_secret" secretKey: "client_secret"
- objectName: "veles-app-secrets__VELES_SESSION_SECRET" - objectName: "veles-app__session-secret"
secretPath: "kv/data/atlas/veles/app-secrets" secretPath: "kv/data/atlas/veles/app-secrets"
secretKey: "VELES_SESSION_SECRET" secretKey: "VELES_SESSION_SECRET"
- objectName: "veles-app-secrets__VELES_BYOK_ENCRYPTION_KEY" - objectName: "veles-app__byok-encryption-key"
secretPath: "kv/data/atlas/veles/app-secrets" secretPath: "kv/data/atlas/veles/app-secrets"
secretKey: "VELES_BYOK_ENCRYPTION_KEY" secretKey: "VELES_BYOK_ENCRYPTION_KEY"
secretObjects: secretObjects:
@ -40,15 +40,31 @@ spec:
- secretName: veles-runtime-secrets - secretName: veles-runtime-secrets
type: Opaque type: Opaque
data: data:
- objectName: veles-db__DATABASE_URL - objectName: veles-db__database-url
key: DATABASE_URL key: DATABASE_URL
- objectName: veles-db__POSTGRES_USER - objectName: veles-db__user
key: VELES_DATABASE_USER key: VELES_DATABASE_USER
- objectName: veles-db__POSTGRES_PASSWORD - objectName: veles-db__password
key: VELES_DATABASE_PASSWORD key: VELES_DATABASE_PASSWORD
- objectName: veles-oidc__client_secret - objectName: veles-oidc__client-secret
key: VELES_OIDC_CLIENT_SECRET key: VELES_OIDC_CLIENT_SECRET
- objectName: veles-app-secrets__VELES_SESSION_SECRET - objectName: veles-app__session-secret
key: VELES_SESSION_SECRET key: VELES_SESSION_SECRET
- objectName: veles-app-secrets__VELES_BYOK_ENCRYPTION_KEY - objectName: veles-app__byok-encryption-key
key: VELES_BYOK_ENCRYPTION_KEY key: VELES_BYOK_ENCRYPTION_KEY
---
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: veles-codex-cli
namespace: veles
spec:
provider: vault
parameters:
vaultAddress: "http://vault.vault.svc.cluster.local:8200"
roleName: "veles-sim"
objects: |
- objectName: "auth.json"
secretPath: "kv/data/atlas/veles/codex-cli"
secretKey: "auth.json"
filePermission: "0440"

View File

@ -12,6 +12,7 @@ kind: ServiceAccount
metadata: metadata:
name: veles-frontend name: veles-frontend
namespace: veles namespace: veles
automountServiceAccountToken: false
imagePullSecrets: imagePullSecrets:
- name: harbor-regcred - name: harbor-regcred
--- ---
@ -25,6 +26,15 @@ imagePullSecrets:
--- ---
apiVersion: v1 apiVersion: v1
kind: ServiceAccount kind: ServiceAccount
metadata:
name: veles-retention
namespace: veles
automountServiceAccountToken: false
imagePullSecrets:
- name: harbor-regcred
---
apiVersion: v1
kind: ServiceAccount
metadata: metadata:
name: veles-vault-sync name: veles-vault-sync
namespace: veles namespace: veles

View File

@ -11,7 +11,7 @@ spec:
- name: http - name: http
port: 80 port: 80
protocol: TCP protocol: TCP
targetPort: http targetPort: 8796
selector: selector:
app: veles-backend app: veles-backend
--- ---
@ -27,6 +27,6 @@ spec:
- name: http - name: http
port: 80 port: 80
protocol: TCP protocol: TCP
targetPort: http targetPort: 8080
selector: selector:
app: veles-frontend app: veles-frontend