Config Connector

Config Connector est un opérateur pour GKE, qui permet de gérer les ressources Google Cloud via des manifestes Kubernetes.

Il peut remplacer Terraform ou travailler conjointement avec Terraform.

Ce memo détaille :

  • comment déployer Config Connector sur un cluster GKE
  • comment utiliser Config Connector pour gérer des ressources GCP

Liens utiles

Créer un cluster Kubernetes de test

gcloud container clusters create "mon-cluster" --zone "europe-west1-b" \
  --machine-type "n1-standard-2" --image-type "COS" --disk-size "100" \
  --num-nodes "1" --enable-autoscaling --min-nodes "1" --max-nodes "2" \
  --network "default" --enable-stackdriver-kubernetes --enable-ip-alias \
  --addons ConfigConnector --workload-pool mon-projet-123456.svc.id.goog \
  --cluster-version latest
  • --addons ConfigConnector permet d’installer automatiquement ConfigConnector sur le cluster
  • --workload-pool PROJECT_ID.svc.id.goog permet d’activer Workload Identity sur le cluster

Si on est sur un cluster déjà existant il est possible d’activer Workload Identity à postériori :

Activer Workload Identity sur le cluster :

gcloud container clusters update CLUSTER_NAME \
  --workload-pool=PROJECT_ID.svc.id.goog

Exemple:

gcloud container clusters update mon-cluster \
  --workload-pool=mon-projet-123456.svc.id.goog

Activer Workload Identity sur le node-pool :

gcloud container node-pools update NODE_POOL \
    --workload-metadata=GKE_METADATA \
    --cluster CLUSTER_NAME

Exemple :

gcloud container node-pools update default-pool \
    --workload-metadata=GKE_METADATA \
    --cluster mon-cluster

Configuration de ConfigConnector

L’objet suivant est automatiquement créé et configure par défaut le mode namespaced qui permet d’utiliser config connector au sein de namespaces.

apiVersion: core.cnrm.cloud.google.com/v1beta1
kind: ConfigConnector
metadata:
  name: configconnector.core.cnrm.cloud.google.com
...
spec:
  mode: namespaced
...

L’autre mode possible est cluster.

Créer un namespace Kubernetes

Comme nous utilisons le mode namespaced, nous avons besoin de créer un namespace. Les ressources GCP gérées par Config Connector seront déclarées dans ce namespace.

kubectl create ns mon-namespace

Ajouter une annotation sur le namespace pour définir le projet gcp dans lequel seront créées le resources GCP gérées par config connector :

kubectl  annotate ns mon-namespace cnrm.cloud.google.com/project-id=mon-projet-123456
namespace/mon-namespace annotated

Créer un service account GCP

Nous créons un service account GCP avec lequel les différentes ressources GCP seront gérées :

gcloud iam service-accounts create NAMESPACE_GSA --project HOST_PROJECT_ID

Remplacer l’élément suivant :

  • NAMESPACE_GSA par le nom du compte de service Google associé à l’espace de noms
  • HOST_PROJECT_ID par l’ID du projet hôte

Exemple :

gcloud iam service-accounts create configconnector-test --project mon-projet-123456
Created service account [configconnector-test].

Donner au service account GCP les droits Owner sur le projet

Afin que le service account GCP puisse créer des ressources GCP dans le projet, il faut lui attribuer des droits forts, par exemple owner du projet :

gcloud projects add-iam-policy-binding MANAGED_PROJECT_ID \
    --member="serviceAccount:NAMESPACE_GSA@HOST_PROJECT_ID.iam.gserviceaccount.com" \
    --role="roles/owner"

Remplacer l’élément suivant :

  • MANAGED_PROJECT_ID par l’ID du projet géré
  • NAMESPACE_GSA par le nom du compte de service Google associé à l’espace de noms
  • HOST_PROJECT_ID par l’ID du projet hôte

Exemple :

gcloud projects add-iam-policy-binding mon-projet-123456 \
    --member="serviceAccount:configconnector-test@mon-projet-123456.iam.gserviceaccount.com" \
    --role="roles/owner"

Impersonnification via Workload Identity

Cette étape permet de lier le service account GCP (IAM) avec le service account Kubernetes de Config Connector (SA cnrm-controller-manager-mon-namespace dans le du namespace cnrm-system).

Ainsi, le service account Kubernetes pourra obtenir les droits du service account GCP.

gcloud iam service-accounts add-iam-policy-binding \
NAMESPACE_GSA@HOST_PROJECT_ID.iam.gserviceaccount.com \
    --member="serviceAccount:HOST_PROJECT_ID.svc.id.goog[cnrm-system/cnrm-controller-manager-NAMESPACE]" \
    --role="roles/iam.workloadIdentityUser" \
    --project HOST_PROJECT_ID

Remplacer l’élément suivant :

  • HOST_PROJECT_ID par l’ID du projet hôte
  • NAMESPACE_GSA par le nom du compte de service Google associé à l’espace de noms
  • NAMESPACE par l’espace de noms

Exemple :

gcloud iam service-accounts add-iam-policy-binding \
configconnector-test@mon-projet-123456.iam.gserviceaccount.com \
    --member="serviceAccount:mon-projet-123456.svc.id.goog[cnrm-system/cnrm-controller-manager-mon-namespace]" \
    --role="roles/iam.workloadIdentityUser" \
    --project mon-projet-123456

Le namespace cnrm-system est le namespace dans lequel config connector créé le service account.

Création du contexte pour Config Connector

Copier le fichier YAML suivant dans un fichier nommé configconnectorcontext.yaml :

apiVersion: core.cnrm.cloud.google.com/v1beta1
kind: ConfigConnectorContext
metadata:
  # you can only have one ConfigConnectorContext per namespace
  name: configconnectorcontext.core.cnrm.cloud.google.com
  namespace: NAMESPACE
spec:
  googleServiceAccount: "NAMESPACE_GSA@HOST_PROJECT_ID.iam.gserviceaccount.com"

Remplacer l’élément suivant :

  • NAMESPACE par le nom de l’espace de noms.
  • NAMESPACE_GSA par le nom du compte de service Google associé à l’espace de noms
  • HOST_PROJECT_ID par l’ID du projet hôte

Exemple :

apiVersion: core.cnrm.cloud.google.com/v1beta1
kind: ConfigConnectorContext
metadata:
  # you can only have one ConfigConnectorContext per namespace
  name: configconnectorcontext.core.cnrm.cloud.google.com
  namespace: mon-namespace
spec:
  googleServiceAccount: "configconnector-test@mon-projet-123456.iam.gserviceaccount.com"

Appliquer le fichier sur le cluster à l’aide de la commande kubectl suivante :

kubectl apply -f configconnectorcontext.yaml

Créer une ressource avec Config Connector

Voici un exemple de manifeste pour créer un bucket GCS :

Copier le fichier YAML suivant dans un fichier nommé bucket.yaml :

apiVersion: storage.cnrm.cloud.google.com/v1beta1
kind: StorageBucket
metadata:
  annotations:
    cnrm.cloud.google.com/force-destroy: "false"
  labels:
    label-one: "value-one"
  # StorageBucket names must be globally unique
  name: mon-bucket
  namespace: mon-namespace
spec:
  lifecycleRule:
    - action:
        type: Delete
      condition:
        age: 7
  versioning:
    enabled: true
  cors:
    - origin: ["http://example.appspot.com"]
      responseHeader: ["Content-Type"]
      method: ["GET", "HEAD", "DELETE"]
      maxAgeSeconds: 3600

/!\ Ne pas oublier de mentionner le namespace !

Appliquer le fichier sur le cluster à l’aide de la commande kubectl suivante :

kubectl apply -f bucket.yaml

Au bout de quelques secondes un bucket doit être créé dans le projet.

Lister les ressources GCP managées par Config Connector

kubectl -n mon-namespace get gcp
NAME                                                          AGE   READY   STATUS     STATUS AGE
storagebucket.storage.cnrm.cloud.google.com/mon-bucket  79m   True    UpToDate   79m

Empecher la suppression accidentelle d’une ressource gérée par Config Connector

Il suffit de mettre l’annotation suivante sur la ressource :

Annotations:
  cnrm.cloud.google.com/deletion-policy: abandon

“Adopter” une resource existante

On installe la ligne de commande config connector

$ gcloud components install config-connector

Dans cet exemple on “adopte” une instance de VM :

$ config-connector export //compute.googleapis.com/compute/v1/projects/mon-projet-123456/zones/europe-west1-b/instances/mon-cluster-default-pool-5b5018b9-qp4n > mon-instance.yaml

pour obtenir le link à exporter :

$ gcloud compute instances describe mon-cluster-default-pool-5b5018b9-qp4n --format "value(selfLink)"
https://www.googleapis.com/compute/v1/projects/mon-projet-123456/zones/europe-west1-b/instances/mon-cluster-default-pool-5b5018b9-qp4n

puis enlever https://www et remplacer par compute

Enfin, adopter la ressouce :

kubectl apply -f mon-instance.yaml

La ressource doit maintenant apparaître :

$ kubectl -n mon-namespace get gcp
NAME                                                      AGE   READY   STATUS     STATUS AGE
computeinstance.compute.cnrm.cloud.google.com/ma-vm       52m   True    UpToDate   52m

NAME                                                          AGE   READY   STATUS     STATUS AGE
storagebucket.storage.cnrm.cloud.google.com/mon-bucket  79m   True    UpToDate   79m