Nous avons comme bonne pratique d’utiliser de l’infra-as-code, notamment via Terraform lorsqu’il s’agit de GCP. Via une seule commande l’infrastructure complète du projet est créée, détruite ou mise à jour.
Voyons dans cet article comment créer un cluster GKE, une base de données Cloud SQL Postgres et comment sécuriser l’accès de nos applications à l’instance Cloud SQL. Nous utiliserons la fonctionnalité Workload Identity recommandée par Google (via Cloud SQL Proxy).
Bien sûr, en utilisant Terraform.
Pour ce faire nous allons créer :
- un cluster GKE utilisant Workload Identity ;
- un Service Account IAM autorisé à accéder à la base de données Cloud SQL ;
- un Service Account Kubernetes et l’associer au Service Account IAM ;
- un déploiement utilisant le design pattern Sidecar pour attacher le conteneur Cloud SQL Proxy avec notre application.
Schéma : sécuriser l’accès à Cloud SQL depuis K8s via KSA et GSA
1. Créer le cluster GKE via Terraform
resource "google_container_cluster" "<name>" { project = <project_id> provider = google-beta name = <cluster_name> monitoring_service = "monitoring.googleapis.com/kubernetes" logging_service = "logging.googleapis.com/kubernetes" node_config { oauth_scopes = [ " " " ] workload_metadata_config { node_metadata = "GKE_METADATA_SERVER" } } workload_identity_config { identity_namespace = "<project_id>.svc.id.goog" } }
Pour créer le cluster GKE via Terraform, il est nécessaire d’utiliser la ressource google_container_cluster. Le YAML ci-dessus correspond au minimum nécessaire pour obtenir un cluster fonctionnel et permettant l’usage de Workload Identity.
Workload Identity est le moyen recommandé pour accéder à des services GCP depuis le cluster Kubernetes (GKE).
Plusieurs choses sont à noter :
- L’utilisation d’un provider google-beta permettant l’accès à des fonctionnalités bêtas.
workload_metadata_config
(bêta) permettant de configurer l’exposition des metadata des workloads sur les nœuds du pool. Dans notre cas, la metadataGKE_METADATA_SERVER
permet d’activer Workload Identity sur le nœud.workload_identity_config
(bêta) permettant à un compte de service Kubernetes d’agir comme un compte de service utilisateur Google IAM via Workload Identity. Pour le moment l’identity namespace autorisé est celui par défaut sur le projet :.svc.id.goog
devstorage.read_only
permettant au cluster de lire le dépôt privé GCR pour récupérer l’image Docker de l’application
Une fois le cluster créé et configuré pour utiliser la fonctionnalité de Workload Identity, nous devons à présent créer un Service Account IAM (Google) capable d’accéder à la base de données.
Attention ! Nous parlons ici de « Service Account » (compte de service, utilisés pour des programmes / utilisateurs non humains) dans plusieurs contextes. D’un côté, les Service Account IAM, propres à GCP, et représentant une identité au sein de GCP. De l’autre, les Service Account Kubernetes, représentant une identité au sein d’un cluster Kubernetes. Les deux sont des notions bien différentes, comme le serait par exemple la notion d’identité utilisateur propre à votre application, sans lien avec celle de GCP. Et ce que nous allons voir ici, c’est justement comment lier ces Service Account GCP / Kubernetes. – Horgix
2. Créer le Service Account IAM
resource "google_service_account" "gsa" { account_id = <service_account_name> project = <project_id> }
Pour créer le Service Account IAM, nous utilisons google_service_account
qui n’a besoin que d’un nom account_id
et d’un projet associé project
. À noter qu’une description et un nom d’affichage peuvent être ajoutés pour plus de lisibilité.
Associer le droit d’accès à Cloud SQL
resource "google_project_iam_member" "cloud-sql-client" { project = <project_id> role = "roles/cloudsql.client" member = "serviceAccount:${google_service_account.gsa.email}" }
Afin d’associer le rôle roles/cloudsql.client
permettant la connexion aux instances Cloud SQL, nous utilisons la ressource google_project_iam_member. Nous précisons que le membre qui acquiert ce rôle est le Service Account précédemment créé.
3. Créer le Service Account Kubernetes
resource "kubernetes_service_account" "ksa" { metadata { name = <kubernetes_sa_name> annotations = { "iam.gke.io/gcp-service-account" = google_service_account.gsa.email } } }
Afin de permettre à nos Pods d’accéder à Cloud SQL, nous devons créer un Service Account Kubernetes qui est associé au Service Account IAM précédemment créé. Nous utilisons kubernetes_service_account. L‘association se fait via l’annotation iam.gke.io/gcp-service-account
en précisant l’email du Service Account IAM.
Association du rôle workload identity entre le SA IAM et le SA K8s
Afin d’associer le rôle roles/iam.workloadIdentityUser du Service Account IAM et le Service Account Kubernetes, il est possible de passer par la ressource google_service_account_iam_binding :
resource "google_service_account_iam_binding" "gke_gsa_ksa_binding" { service_account_id = google_service_account.gsa.name role = "roles/iam.workloadIdentityUser" members = [ "serviceAccount:<project_id>.svc.id.goog[default/<kubernetes_sa_name>]" ] }
En précisant l’identifiant du Service Account IAM déjà créé service_account_id
; et le Service Account Kubernetes exposé (défini plus haut) members/serviceAccount
4. Déployer notre application et son Sidecar configuré pour utiliser le SA K8s
La dernière étape pour permettre à notre application d’accéder à sa base de données Cloud SQL est de configurer le déploiement. Nous y ajoutons le Proxy Cloud SQL configuré pour utiliser le SA Kubernetes.
apiVersion: apps/v1 kind: Deployment metadata: name: <app-name> spec: selector: matchLabels: app: <app-name> template: metadata: labels: app: <app-name> spec: serviceAccountName: <kubernetes_sa_name> containers: - name: <app-name> ... - name: cloud-sql-proxy image: gcr.io/cloudsql-docker/gce-proxy:1.17 command: - "/cloud_sql_proxy" - "-instances=<project-id>:<region>:<database-name>=tcp:5432"
L‘information importante est l’entrée serviceAccountName
qui renseigne le Service Account Kubernetes.
À noter que les identifiants pour accéder à la base de données restent nécessaire dans votre application (identifiant, mot de passe, nom de la base de données, le host est localhost).
Cloud SQL Proxy est la méthode recommandée pour se connecter à une instance Cloud SQL car le proxy fournis une méthode de cryptage et d’identification utilisant IAM, ce qui peut grandement aider à garder l’accès à la base de données sécurisé. Sur Kubernetes, lorsque l’application se connecte en utilisant le Cloud SQL Proxy, ce dernier est ajouté à notre Pod en utilisant la méthode du Sidecar container pattern. Le conteneur du Proxy est dans le même Pod que notre application, ce qui permet à l’application de se connecter au Proxy via localhost. C’est plus sécurisé et performant que d’accéder directement à Cloud SQL via l’ adresse IP.
Vous retrouvez toutes les étapes de cet article, sans la partie Terraform, directement dans la documentation Google concernant la connexion de Kubernetes à Cloud SQL.
En conclusion, sécuriser l’accès de ses applications GKE à une base de données Cloud SQL se résume en quelques commandes Terraform. Il serait dommage de s’en passer puisque cela permet d’automatiser, documenter et partager l’infrastructure sans grande complexité.