À la fin de ce tutoriel, vous installerez Crossplane, brancherez le provider AWS, créerez un bucket S3 via une managed resource Kubernetes, puis exposerez une API plateforme (XRD + Composition + Claim) — le tout en
ca-central-1, profil lab, sans console AWS pour provisionner.Niveau : Intermédiaire · Temps estimé : 60–80 min · Versions cibles : Crossplane 2.x / Helm chart stable · provider AWS Upbound (family + S3) · Kubernetes 1.29+ · AWS CLI v2 · Dernière vérification : 2026-09-11 · Region :
ca-central-1Slug :
wow-crossplane-aws· Série : WOW Platform / DevOps · Mot-clé SEO : Crossplane AWS Kubernetes← Connexe : Argo CD GitOps · EKS concepts · CloudFormation premier stack · Hub : Terraform overview
Prérequis
- Cluster Kubernetes lab (kind, k3d, minikube ou EKS jetable) avec
kubectladmin - Helm 3 et AWS CLI v2 ; profil
labavec droits S3 (et IAM lecture pour le debug) - Notions K8s (CRD, Secret, namespace) et un premier contact IaC (CloudFormation ou Terraform)
- Budget d’alerte activé — lab quasi gratuit (bucket S3 vide), suppression obligatoire en fin de session
- Aucun secret réel dans Git : placeholders uniquement
export AWS_PROFILE=lab
export AWS_DEFAULT_REGION=ca-central-1
aws sts get-caller-identity
kubectl cluster-info
helm version
Vérifiez l’identité lab — jamais un compte de production.
Ce que nous allons construire
Lab Crossplane AWS (ca-central-1)
├── Namespace crossplane-system + Helm Crossplane
├── Provider AWS (family + S3)
├── Secret creds + ProviderConfig default
├── Managed Resource : Bucket S3 (privé, BPA)
├── XRD + Composition → API XBucket / Claim
├── Conditions Ready / Synced + events
└── Nettoyage : Claim → MR → Provider → Helm
(Schéma — alt : « Crossplane provisionne un bucket S3 AWS depuis des manifests Kubernetes ».)
Objectif plateforme : les équipes ne touchent plus la console AWS pour un bucket lab ; elles appliquent un Claim YAML, comme un Deployment. GitOps (Argo CD) peut versionner ces Claims ensuite.
Étape 1 — Pourquoi Crossplane (vs Terraform / CloudFormation)
Crossplane transforme Kubernetes en control plane multi-cloud : des Providers installent des CRD pour les ressources cloud ; Crossplane réconcilie l’état désiré (YAML) avec AWS.
| Approche | Forces | Limites |
|---|---|---|
| Console AWS | Rapide pour découvrir | Non reproductible, drift humain |
| CloudFormation | Natif AWS, stacks, drift | Verbose ; hors API K8s |
| Terraform / OpenTofu | Écosystème mature, plan | Processus CLI/état séparé du cluster |
| Crossplane | Même API que les apps (kubectl) ; Compositions = API plateforme |
Courbe CRD ; credentials cluster-scoped |
Quand Crossplane brille : vous avez déjà Kubernetes, vous voulez une API interne (« crée-moi un datastore ») et GitOps unifié apps + infra. Terraform reste excellent pour le landing zone ; Crossplane complète pour le self-service dans le cluster.
Étape 2 — Installer Crossplane avec Helm
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm upgrade --install crossplane crossplane-stable/crossplane
--namespace crossplane-system
--create-namespace
--wait
kubectl -n crossplane-system get pods
kubectl get crd | grep crossplane || true
Attendu : pods Crossplane Running/Ready. Les CRD providers.pkg.crossplane.io, compositions…, compositeresourcedefinitions… apparaissent.
Prod : pinnez une version de chart (
--version X.Y.Z), RBAC restreint, réseau egress contrôlé vers l’API AWS, et préférer IRSA / Pod Identity plutôt que des access keys longues.
Étape 3 — Provider AWS et credentials
Installez le provider (family AWS + paquet S3 — adaptez le tag à une version healthy récente) :
# provider-aws-s3.yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.21.0
kubectl apply -f provider-aws-s3.yaml
kubectl wait provider/provider-aws-s3 --for=condition=Healthy --timeout=300s
kubectl get providers
Créez un fichier credentials local (hors Git) au format INI AWS :
[default]
aws_access_key_id = REPLACE_ME
aws_secret_access_key = REPLACE_ME
kubectl -n crossplane-system create secret generic aws-secret
--from-file=creds=./aws-credentials.txt
# ProviderConfig (Upbound AWS)
cat <<'YAML' | kubectl apply -f -
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-secret
key: creds
YAML
Least privilege lab : politique IAM limitée à s3:CreateBucket, s3:DeleteBucket, s3:PutBucket*, s3:GetBucket*, tags. En EKS prod, basculez vers IRSA ou Pod Identity (credentials.source: IRSA / PodIdentity).
Étape 4 — Premier bucket S3 (managed resource)
Nom de bucket globalement unique — suffixez un random :
SUFFIX=$(openssl rand -hex 4)
echo "SUFFIX=$SUFFIX"
# bucket.yaml — region ca-central-1
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: lab-xp-bucket
labels:
app.kubernetes.io/part-of: wow-crossplane-aws
spec:
forProvider:
region: ca-central-1
tags:
Environment: lab
ManagedBy: crossplane
Project: devops-elastic-hayway
providerConfigRef:
name: default
kubectl apply -f bucket.yaml
kubectl describe bucket.s3.aws.upbound.io lab-xp-bucket
kubectl get bucket.s3.aws.upbound.io lab-xp-bucket -o yaml | sed -n '/status:/,$p'
Attendu : conditions Synced=True, Ready=True. Vérification AWS :
aws s3api list-buckets --query "Buckets[?starts_with(Name, 'lab-xp')]" --output table
# ou récupérez le nom physique via status.atProvider
Bloquez le public dès la Composition (étape suivante) ; ici le lab minimal prouve le chemin control plane → AWS.
Étape 5 — API plateforme : XRD, Composition, Claim
Les équipes ne devraient pas manipuler les CRD bas niveau Bucket. Vous exposez une API métier.
1. XRD (CompositeResourceDefinition) — API XBucket / claim BucketClaim :
# xrd-xbucket.yaml (extrait conceptuel)
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xbuckets.platform.deh.local
spec:
group: platform.deh.local
names:
kind: XBucket
plural: xbuckets
claimNames:
kind: BucketClaim
plural: bucketclaims
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
region:
type: string
default: ca-central-1
environment:
type: string
default: lab
required: [region]
required: [parameters]
2. Composition — mappe le claim vers un Bucket Upbound + tags + region :
# composition-xbucket.yaml (idée)
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: xbuckets.aws.s3
labels:
provider: aws
spec:
compositeTypeRef:
apiVersion: platform.deh.local/v1alpha1
kind: XBucket
resources:
- name: s3-bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: ca-central-1
tags:
ManagedBy: crossplane
providerConfigRef:
name: default
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.environment
toFieldPath: spec.forProvider.tags.Environment
3. Claim (ce que le développeur applique) :
apiVersion: platform.deh.local/v1alpha1
kind: BucketClaim
metadata:
name: app-assets
namespace: default
spec:
parameters:
region: ca-central-1
environment: lab
kubectl apply -f xrd-xbucket.yaml
kubectl apply -f composition-xbucket.yaml
kubectl apply -f claim-app-assets.yaml
kubectl get bucketclaim,xbucket,bucket.s3.aws.upbound.io
C’est le cœur platform engineering : une API interne versionnée, des garde-fous (region forcée ca-central-1, tags obligatoires), et GitOps possible avec Argo CD.
Étape 6 — Day-2 : Ready, Synced, events
kubectl get bucket.s3.aws.upbound.io -o wide
kubectl describe bucket.s3.aws.upbound.io lab-xp-bucket | sed -n '/Conditions/,/Events/p'
kubectl -n crossplane-system logs deploy/crossplane --tail=80
| Condition | Signification |
|---|---|
| Synced | Le desired state a été poussé / lu sans erreur API |
| Ready | La ressource externe est utilisable |
Drift manuel (console AWS) : Crossplane tente de reconcilier selon la politique du provider. En prod, couplez avec policy-as-code (OPA/Gatekeeper) et scans IaC (Trivy) dans le CI.
Nettoyage (obligatoire)
Ordre : Claims / composites → managed resources → ProviderConfig / Secret → Provider → Helm.
kubectl delete bucketclaim app-assets --ignore-not-found
kubectl delete bucket.s3.aws.upbound.io lab-xp-bucket --wait=true
# Attendez la disparition AWS avant de casser les creds
aws s3api list-buckets --query "Buckets[].Name" --output text | tr 't' 'n' | grep lab-xp || true
kubectl delete providerconfig.aws.upbound.io default --ignore-not-found
kubectl -n crossplane-system delete secret aws-secret --ignore-not-found
kubectl delete provider provider-aws-s3 --ignore-not-found
helm uninstall crossplane -n crossplane-system
kubectl delete namespace crossplane-system --ignore-not-found
Sur un cluster jetable (kind), détruire le cluster suffit — vérifiez tout de même qu’aucun bucket lab ne traîne dans ca-central-1.
Coûts du lab
| Ressource | Ordre de grandeur |
|---|---|
| Bucket S3 vide | ≈ 0 USD (requêtes négligeables) |
| Control plane Crossplane | Coût nœuds K8s lab seulement |
| EKS (si utilisé) | ≈ 0,10 USD/h control plane — delete vite |
Activez une alerte budget AWS ; ne laissez jamais un EKS « oublié » overnight.
Erreurs fréquentes
| Symptôme | Cause | Correction |
|---|---|---|
| Provider pas Healthy | Image / registry / DNS | kubectl describe provider ; retry ; pin version |
| Bucket Synced=False | Creds / région / nom pris | Relire events ; Secret creds ; suffixe unique |
| AccessDenied S3 | IAM trop strict | Ajouter actions bucket ; vérifier compte lab |
| Claim sans Composition | XRD/Composition mal liés | compositionSelector / compositionRef ; labels |
| Bucket orphelin AWS | Delete MR trop tôt / finalizer | Attendre Ready delete ; delete bucket CLI en dernier recours lab |
FAQ
Crossplane remplace-t-il Terraform ?
Non. Terraform (ou OpenTofu) reste fort pour le bootstrap et les grands modules partagés. Crossplane excelle quand l’infra doit être une API Kubernetes self-service, surtout avec GitOps.
Faut-il EKS pour ce lab ?
Non. kind/k3d suffisent pour apprendre CRD + provider. EKS devient pertinent pour IRSA/Pod Identity et un vrai réseau AWS.
Où stocker les credentials ?
Secret Kubernetes hors Git en lab. En prod : IRSA, Pod Identity, ou vault externe (External Secrets / Vault) — jamais d’access key longue dans un repo.
Comment versionner ça avec Argo CD ?
Mettez XRD, Composition, Claims (et éventuellement Providers) dans Git ; Argo CD sync le path. Les managed resources suivent alors le même flux que les Deployments.
Quelle région utiliser ?
Ce parcours force ca-central-1 (Canada). Alignez tags, budgets et data residency sur la même région.
XRD vs Composition ?
Le XRD définit l’API (schéma Claim). La Composition définit comment réaliser cette API (ressources AWS concrètes + patches).
Quiz (3 questions)
1. Qu’est-ce qu’une managed resource Crossplane ?
– A. Un Pod système uniquement
– B. Un CR Kubernetes réconcilié vers une ressource cloud (ex. Bucket S3)
– C. Un fichier Terraform state
2. À quoi sert une Composition ?
– A. Remplacer etcd
– B. Mapper une API XRD/Claim vers des ressources cloud concrètes
– C. Facturer AWS automatiquement
3. Pourquoi préférer IRSA/Pod Identity en prod EKS ?
– A. C’est plus joli dans la console
– B. Éviter les access keys longues dans le cluster ; identité liée au ServiceAccount
– C. Crossplane refuse les Secrets
Réponses : 1‑B · 2‑B · 3‑B
Pour aller plus loin
- Compositions avancées : functions (Go/Python/KCL), patch sets, readiness checks
- Enchaîner : Claims dans Git + Argo CD GitOps
- Comparer IaC : Terraform overview, lab CloudFormation, série WOW Pulumi vs Terraform
- EKS day-2 : EKS concepts, Pod Identity (série WOW)
Maillage WOW / Platform
| Série | WOW ×50 — Platform Engineering & GitOps |
| Voisins | wow-platform-engineering-2026 · wow-argo-cd-gitops · wow-pulumi-vs-terraform · wow-backstage-idp |
| Hubs live | AWS · Terraform · Kubernetes (menus du site) |
Meta publication (SEO) — Publish HOLD
- Title SEO : Crossplane AWS : infra comme Kubernetes (lab 2026)
- Meta description (≤ 160) : Installez Crossplane, branchez le provider AWS et créez un bucket S3 via kubectl en ca-central-1. Lab XRD, Composition et Claim pour une API plateforme.
- Image mise en avant :
assets/web/devopelastichayway/cover-wow-crossplane-aws-1200x630.webp - Cover alt : Crossplane provisionne l’infra AWS depuis Kubernetes
- Catégorie : DevOps / Platform · Niveau : Intermédiaire
- KW principal : Crossplane AWS Kubernetes · Secondaires : Crossplane S3, provider AWS Crossplane, XRD Composition Claim, infra as Kubernetes
- Schema : HowTo + FAQPage + Article
- URL cible : https://devopelastichayway.com/tutoriels/wow-crossplane-aws/
- Statut : Publish HOLD — draft only, pas de Rank Math live sans feu vert
- Region lab :
ca-central-1
Pour aller plus loin — hubs live
Retour parcours Catalogue Tutoriels — hub de la série et leçons sœurs.