Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d896461
fix(observability): guard spoke scrapers against missing/None securit…
May 20, 2026
e9bd3b3
feat(exposure): add CloudFront exposure mode for domain-less deployments
May 20, 2026
094f301
feat(backstage): support exposure_mode for ALB ingress
May 21, 2026
6baad2c
fix(backstage): use CNOE-customized image (public.ecr.aws/seb-demo/ba…
allamand May 22, 2026
8bafa5f
feat(cloudfront): ALB URL rewrite, IDC/SCIM automation, Backstage Git…
May 26, 2026
e1d2332
fix: enable OSS LBC on hub (Auto Mode ELB lacks path rewrite support)
May 27, 2026
8ed6809
feat(gitlab): dedicated NLB + CloudFront for GitLab in cloudfront mode
May 27, 2026
765f0e2
temp: add gitlab root password overlay for testing
May 27, 2026
5d96585
fix: set preserveResourcesOnDeletion on bootstrap appset
May 27, 2026
f979844
feat: add argocd-refresh-token script to scripts/
May 27, 2026
7658a80
refactor: move automation scripts from platform/infra/terraform/scrip…
May 27, 2026
5feb0ed
fix: add terminate-op for stuck operations in argocd-sync.sh
May 27, 2026
0bf605a
docs: add ArgoCD recovery procedures to troubleshoot-platform skill
May 27, 2026
83a3824
docs: add CRITICAL warning about ArgoCD app deletion being destructive
May 27, 2026
1900760
fix: make argocd-refresh-token.sh safe to source
May 27, 2026
172ec4c
fix: use SCRIPT_DIR directly for argocd_token_automation.py path
May 27, 2026
a197cea
fix: use readlink -f for robust path resolution when sourced
May 27, 2026
6c52f60
fix: support zsh for BASH_SOURCE path resolution
May 27, 2026
4f2b674
fix: remove spoke fleet members (clusters don't exist yet)
May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ tasks:
cmds:
- task: "{{.PROVIDER}}:hub:update"

hub-cloudfront:
desc: Create CloudFront distribution for domain-less exposure
vars:
PROVIDER:
sh: yq '.clusterProvider // "kind-crossplane"' {{.CONFIG_FILE}}
cmds:
- task: "{{.PROVIDER}}:hub:cloudfront"

observability-seed:
desc: Seed observability credentials (AMP/AMG) into Secrets Manager (run after workspaces are created)
vars:
Expand Down
324 changes: 316 additions & 8 deletions cluster-providers/kind-crossplane/Taskfile.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,61 @@ spec:
--policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy \
--access-scope type=cluster 2>/dev/null || true

echo "=== Create KRO capability ==="
KRO_STATUS=$(aws eks describe-capability \
--cluster-name "$CLUSTER_NAME" \
--capability-name "kro" \
--region "$AWS_REGION" \
--query 'capability.status' \
--output text 2>/dev/null || echo "NOT_FOUND")
if [ "$KRO_STATUS" = "NOT_FOUND" ]; then
aws eks create-capability \
--region "$AWS_REGION" \
--cluster-name "$CLUSTER_NAME" \
--capability-name "kro" \
--type KRO \
--role-arn "$CAPABILITY_ROLE_ARN" \
--delete-propagation-policy RETAIN
echo "KRO capability created"
else
echo "KRO capability exists: $KRO_STATUS"
fi

echo "=== Create ACK capability ==="
ACK_STATUS=$(aws eks describe-capability \
--cluster-name "$CLUSTER_NAME" \
--capability-name "ack" \
--region "$AWS_REGION" \
--query 'capability.status' \
--output text 2>/dev/null || echo "NOT_FOUND")
if [ "$ACK_STATUS" = "NOT_FOUND" ]; then
aws eks create-capability \
--region "$AWS_REGION" \
--cluster-name "$CLUSTER_NAME" \
--capability-name "ack" \
--type ACK \
--role-arn "$CAPABILITY_ROLE_ARN" \
--delete-propagation-policy RETAIN
echo "ACK capability created"
else
echo "ACK capability exists: $ACK_STATUS"
fi

echo "=== Wait for KRO and ACK ACTIVE ==="
for CAP in kro ack; do
for i in $(seq 1 40); do
S=$(aws eks describe-capability \
--cluster-name "$CLUSTER_NAME" \
--capability-name "$CAP" \
--region "$AWS_REGION" \
--query 'capability.status' \
--output text 2>/dev/null || echo "UNKNOWN")
[ "$S" = "ACTIVE" ] && echo "$CAP: ACTIVE" && break
echo "$CAP: $S ($i/40)"
sleep 15
done
done

echo "=== Done ==="
echo "ARN: arn:aws:eks:${AWS_REGION}:${AWS_ACCOUNT_ID}:cluster/${CLUSTER_NAME}"
aws eks describe-capability \
Expand Down
11 changes: 11 additions & 0 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,17 @@
}
}
},
"exposure": {
"type": "object",
"properties": {
"mode": {
"type": "string",
"enum": ["domain", "cloudfront"],
"default": "domain",
"description": "Exposure mode. 'domain' uses HTTPS with ACM cert and custom domain. 'cloudfront' uses HTTP ALB behind CloudFront (no custom domain needed)."
}
}
},
"argocdCapability": {
"type": "object",
"properties": {
Expand Down
11 changes: 11 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,14 @@ identityCenter:
# EKS ArgoCD Capability
argocdCapability:
name: "argocd"

# Exposure mode: "domain" (HTTPS + ACM cert + custom domain) or "cloudfront" (HTTP ALB behind CloudFront)
exposure:
mode: "domain"

# Console admin role name (used by Backstage templates for EKS access entries)
adminRoleName: "<console-role-name>" # e.g. WSParticipantRole

# ML model S3 bucket (created by Taskfile if enabled)
modelS3Bucket:
enabled: false
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,92 @@ spec:
fromFieldPath: spec.argoCDRoleArn
toFieldPath: spec.forProvider.principalArn

# Create KRO and ACK EKS Capabilities on the spoke cluster
- name: eks-capabilities-job
base:
apiVersion: kubernetes.crossplane.io/v1alpha2
kind: Object
spec:
providerConfigRef:
name: default
forProvider:
manifest:
apiVersion: batch/v1
kind: Job
metadata:
name: ""
namespace: crossplane-system
spec:
backoffLimit: 5
ttlSecondsAfterFinished: 300
template:
spec:
serviceAccountName: crossplane
restartPolicy: OnFailure
volumes:
- name: aws-creds
secret:
secretName: aws-credentials
containers:
- name: create-capabilities
image: amazon/aws-cli:latest
env:
- name: AWS_SHARED_CREDENTIALS_FILE
value: /tmp/.aws/credentials
- name: CLUSTER_NAME
value: ""
- name: AWS_REGION
value: ""
- name: ROLE_ARN
value: ""
volumeMounts:
- name: aws-creds
mountPath: /tmp/.aws
readOnly: true
command: ["/bin/bash", "-c"]
args:
- |
set -euo pipefail
aws eks wait cluster-active --name "$CLUSTER_NAME" --region "$AWS_REGION"
for CAP_TYPE in KRO ACK; do
CAP_NAME=$(echo "$CAP_TYPE" | tr '[:upper:]' '[:lower:]')
EXISTING=$(aws eks describe-capability --cluster-name "$CLUSTER_NAME" --capability-name "$CAP_NAME" --region "$AWS_REGION" --query 'capability.status' --output text 2>/dev/null || echo "NOT_FOUND")
if [ "$EXISTING" = "NOT_FOUND" ]; then
aws eks create-capability --region "$AWS_REGION" --cluster-name "$CLUSTER_NAME" --capability-name "$CAP_NAME" --type "$CAP_TYPE" --role-arn "$ROLE_ARN" --delete-propagation-policy RETAIN
echo "$CAP_NAME capability created"
else
echo "$CAP_NAME capability exists: $EXISTING"
fi
done
for CAP_NAME in kro ack; do
for i in $(seq 1 40); do
S=$(aws eks describe-capability --cluster-name "$CLUSTER_NAME" --capability-name "$CAP_NAME" --region "$AWS_REGION" --query 'capability.status' --output text 2>/dev/null || echo "UNKNOWN")
[ "$S" = "ACTIVE" ] && echo "$CAP_NAME: ACTIVE" && break
sleep 15
done
done
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.clusterName
toFieldPath: metadata.annotations[crossplane.io/external-name]
- type: FromCompositeFieldPath
fromFieldPath: spec.clusterName
toFieldPath: spec.forProvider.manifest.metadata.name
transforms:
- type: string
string:
type: Format
fmt: "%s-capabilities"
- type: FromCompositeFieldPath
fromFieldPath: spec.clusterName
toFieldPath: spec.forProvider.manifest.spec.template.spec.containers[0].env[1].value
- type: FromCompositeFieldPath
fromFieldPath: spec.region
toFieldPath: spec.forProvider.manifest.spec.template.spec.containers[0].env[2].value
- type: FromCompositeFieldPath
fromFieldPath: spec.argoCDRoleArn
toFieldPath: spec.forProvider.manifest.spec.template.spec.containers[0].env[3].value

# EKS Cluster with Auto Mode enabled
- name: eks-cluster
base:
Expand Down
10 changes: 9 additions & 1 deletion gitops/addons/charts/argo-workflows/templates/ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@ metadata:
namespace: argo
annotations:
alb.ingress.kubernetes.io/target-type: ip
{{- if eq (default "domain" .Values.exposure_mode) "cloudfront" }}
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80}]'
{{- else }}
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/ssl-redirect: '443'
{{- end }}
alb.ingress.kubernetes.io/transforms.argo-server: |
[{"type":"url-rewrite","urlRewriteConfig":{"rewrites":[{"regex":"^\\/argo-workflows\\/?(.*)$","replace":"/$1"}]}}]
spec:
ingressClassName: "platform"
ingressClassName: platform
rules:
{{- if eq (default "domain" .Values.exposure_mode) "cloudfront" }}
- http:
{{- else }}
- host: {{ .Values.ingress_domain_name }}
http:
{{- end }}
paths:
- path: /argo-workflows
pathType: Prefix
Expand Down
Loading