Lorsque vous déployez des centaines d'applications conteneurisées, l'intégration d'identifiants statiques dans chaque image crée un risque de sécurité lié à la « dernière clé » et augmente la charge de maintenance. Déployez KMS Agent en tant que sidecar dans votre cluster ACK pour récupérer dynamiquement des secrets depuis Key Management Service (KMS) via le mécanisme RRSA. Cette approche élimine la nécessité d'intégrer le SDK dans le code de votre application.
Concepts clés
Assurez-vous de bien comprendre les concepts suivants avant de poursuivre :
Qu'est-ce que KMS Agent : KMS Agent est un service proxy HTTP qui récupère les secrets depuis KMS et les met en cache en mémoire. Les applications récupèrent les secrets auprès de l'agent via des requêtes HTTP.
RAM Roles for Service Accounts (RRSA) : RRSA permet d'isoler les autorisations des applications dans un cluster ACK en associant différents rôles RAM à différents Pods. Chaque application endosse un rôle RAM indépendant pour accéder aux API Alibaba Cloud.
Cas d'utilisation
Utilisez KMS Agent avec RRSA dans les scénarios suivants :
-
Éliminer le problème de la « dernière clé »
Le stockage d'identifiants sensibles dans KMS améliore la sécurité, mais l'accès à KMS lui-même nécessite une authentification. S'appuyer sur un AccessKey statique pour accéder à KMS crée un nouveau risque de sécurité.
En activant RRSA sur un cluster ACK, chaque Pod peut endosser un rôle RAM différent et utiliser des identifiants de sécurité temporaires pour accéder à KMS. Cela met en œuvre le principe du moindre privilège et élimine le besoin de clés AccessKey statiques, prévenant ainsi les fuites d'identifiants.
-
Isoler l'accès aux secrets entre les applications et les environnements
Vous devez restreindre l'accès aux secrets entre les environnements de test et de production, ou entre différentes applications, afin d'éviter l'escalade de privilèges et l'accès non autorisé aux secrets.
Avec RRSA, chaque application s'exécute dans un namespace séparé avec son propre compte de service et son rôle RAM. L'attribution d'autorisations différentes à chaque rôle RAM impose un contrôle d'accès granulaire aux secrets KMS.
-
Réduire les coûts d'intégration de KMS à grande échelle
L'intégration du SDK KMS ne s'adapte pas bien aux entreprises disposant de centaines d'applications. Il est difficile de garantir une mise en cache, une reprise après sinistre et des normes de sécurité cohérentes pour toutes les applications, en particulier lorsque les équipes de sécurité, d'exploitation et de développement sont distinctes.
KMS Agent résout ce problème en s'exécutant en tant que sidecar dans le même Pod que votre application. Une fois RRSA activé, l'agent s'authentifie automatiquement auprès de KMS et met les secrets en cache en mémoire. Votre application récupère les secrets depuis l'agent local sans aucune intégration de SDK.
Architecture de la solution
La figure suivante présente un exemple avec deux applications : dev et prod. Chaque application ne peut accéder qu'à ses propres secrets KMS.
Limites
Types de clusters ACK pris en charge : clusters gérés ACK, clusters dédiés ACK, clusters enregistrés ACK et clusters serverless ACK.
Le cluster ACK et l'instance KMS doivent se trouver dans la même région.
Prérequis
Docker est installé et configuré sur votre machine de build.
kubectl est configuré avec un accès à votre cluster ACK.
Vous disposez d'un compte Alibaba Cloud avec les autorisations RAM et KMS requises.
Une instance KMS existe dans la même région que votre cluster ACK.
Go 1.18 ou version ultérieure est installé.
Git est installé.
Procédure
Cette procédure détaille les configurations ACK, RAM et KMS nécessaires pour qu'une application récupère des secrets via KMS Agent. Les développeurs n'ont qu'à créer un secret dans KMS et à le lire localement ; les équipes d'exploitation et de sécurité gèrent la configuration de l'infrastructure au préalable. Aucune intégration de SDK, logique d'authentification ou conception de mise en cache n'est requise dans le code de l'application.
Étape 1 : Générer l'exécutable KMS Agent
Installez Go. Pour obtenir des instructions, consultez le guide d'installation de Go.
-
Téléchargez le code source et les dépendances.
Téléchargez et installez Git depuis le site officiel de Git.
-
Exécutez les commandes suivantes pour cloner le dépôt et télécharger les dépendances :
git clone https://github.com/aliyun/alibabacloud-kms-agent go mod download
-
Dans le répertoire racine du projet, exécutez
go build .pour compiler l'exécutable. Le nom par défaut de l'exécutable estalibabacloud-kms-agentet il est enregistré dans le répertoire racine du projet.Si l'environnement de build et l'environnement de déploiement sont identiques, exécutez directement
go build .. Pour les builds multiplateformes, utilisez les commandes suivantes pour générer un exécutable 64 bits :Environnement de build
Déploiement sur macOS
Déploiement sur Linux
Déploiement sur Windows
macOS
go build .CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build .Linux
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build .go build .CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build .Windows
SET CGO_ENABLED=0 && SET GOOS=darwin && SET GOARCH=amd64 && go build .SET CGO_ENABLED=0 && SET GOOS=linux && SET GOARCH=amd64 && go build .go build . Dans le répertoire racine du projet, vérifiez que l'exécutable
alibabacloud-kms-agentexiste.
Étape 2 : Activer RRSA et autoriser l'accès aux secrets
-
Activez RRSA pour votre cluster ACK.
Activer lors de la création du cluster
Lorsque vous créez un ACK managed cluster et un ACK Edge cluster, vous pouvez activer RRSA dans la section Advanced Options (Optional) de la configuration du cluster.
Activer sur la page d'informations du cluster
Connectez-vous à la console ACK. Dans le volet de navigation de gauche, cliquez sur Clusters.
Sur la page Clusters, cliquez sur le nom de votre cluster. Dans le volet de navigation de gauche, cliquez sur Cluster Information.
Dans l'onglet Basic Information, dans la section Security and Auditing, cliquez sur Enable à côté de RRSA OIDC.
-
Dans la boîte de dialogue Enable RRSA, cliquez sur OK.
RemarqueSur la page Basic Information, lorsque l'état du cluster passe de Updating à Running, la fonctionnalité RRSA est activée pour le cluster.
Accédez à la page des détails du cluster. Dans l'onglet Basic Information, dans la section Security and Auditing, survolez l'état activé à côté de RRSA OIDC pour afficher l'URL du fournisseur et l'ARN. Une fois RRSA activé, cette section affiche l'Provider URL et l'Provider ARN de RRSA OIDC. Vous aurez besoin de ces deux valeurs lors de la configuration de la politique d'approbation du rôle RAM.
-
Créez un rôle RAM avec un fournisseur d'identité comme entité de confiance.
Connectez-vous à la console RAM en tant qu'administrateur RAM. Dans le volet de navigation de gauche, choisissez .
Cliquez sur Create Role. Sur la page de création, cliquez sur Switch to Policy Editor dans le coin supérieur droit.
-
Dans l'éditeur, spécifiez le fournisseur d'identité OIDC. Sélectionnez le mode Visual Editor et configurez les paramètres suivants :
RemarquePour plus d'informations sur les autres modes, consultez Créer un rôle RAM pour un fournisseur d'identité OIDC.
Dans la section Principal, sélectionnez IdP, puis cliquez sur Edit.
-
Dans la boîte de dialogue Add Principal, configurez les paramètres suivants :
IdP Type : Sélectionnez OIDC.
IdP : Une fois RRSA activé, ACK crée un fournisseur d'identité par défaut nommé
ack-rrsa-<cluster_id>, où<cluster_id>correspond à l'ID de votre cluster.Action : Conservez la valeur par défaut
sts:AssumeRole.-
Condition : Ajoutez une nouvelle condition aux côtés des conditions par défaut
oidc:issetoidc:aud:Condition key : Sélectionnez oidc:sub.
Operator : Sélectionnez StringEquals.
-
Condition value : Saisissez
system:serviceaccount:<namespace>:<serviceAccountName>.<namespace>: Le namespace où réside l'application.<serviceAccountName>: Le nom du compte de service.
Cet exemple utilise
system:serviceaccount:rrsa-dev:dev-sa, oùrrsa-devest le namespace Kubernetes etdev-saest le compte de service que vous créerez à l'étape 3.
Dans la boîte de dialogue Create Role, définissez un nom de rôle et cliquez sur OK. Cet exemple utilise
dev-role-for-rrsa.-
Vérifiez la politique d'approbation pour
dev-role-for-rrsa. La politique permet à un compte de service spécifique d'endosser le rôle RAM via RRSA après avoir réussi l'authentification OIDC.{ "Statement": [ { "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "oidc:aud": [ "sts.aliyuncs.com" ], "oidc:iss": [ "https://oidc-ack-cn-hongkong.oss-cn-hongkong.aliyuncs.com/cf01******" ], "oidc:sub": [ "system:serviceaccount:rrsa-dev:dev-sa" ] } }, "Effect": "Allow", "Principal": { "Federated": [ "acs:ram::5269************:oidc-provider/ack-rrsa-cf01******" ] } } ], "Version": "1" }
-
Créez une politique d'autorisation et attachez-la au rôle RAM.
-
Créez une politique d'autorisation. Cet exemple utilise le nom de politique
dev-role-for-rrsa-kms-policyet n'autorise l'accès qu'aux secrets tagués avecenv:dev.
Le contenu de la politique est le suivant :
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": [ "kms:Decrypt", "kms:GetSecretValue" ], "Resource": "*", "Condition": { "StringEqualsIgnoreCase": { "kms:tag/env": [ "dev" ] } } } ] } -
Attachez la politique
dev-role-for-rrsa-kms-policyau rôledev-role-for-rrsa.
-
Étape 3 : Créer un namespace et un compte de service
Un namespace divise un cluster ACK en espaces virtuels logiquement isolés pour différents environnements tels que le développement, les tests et la production. Par défaut, les applications situées dans différents namespaces ne peuvent pas accéder aux ressources des autres. Un compte de service fournit une identité à un Pod et se lie dynamiquement à un rôle RAM via RRSA.
-
Créez un fichier YAML de namespace.
Créez un fichier nommé
namespace.yamlavec le contenu suivant. Cet exemple crée un namespace nommérrsa-dev.apiVersion: v1 kind: Namespace metadata: name: rrsa-dev -
Exécutez la commande suivante pour créer le namespace :
kubectl apply -f namespace.yamlVérifiez que le namespace a été créé :
kubectl get namespacesSi la sortie inclut
rrsa-dev, le namespace a été créé avec succès. -
Créez un fichier YAML de compte de service.
Créez un fichier nommé
serviceaccount.yamlavec le contenu suivant. Cet exemple crée un compte de service nommédev-sadans le namespacerrsa-dev.apiVersion: v1 kind: ServiceAccount metadata: name: dev-sa namespace: rrsa-dev -
Exécutez la commande suivante pour créer le compte de service :
kubectl apply -f serviceaccount.yamlVérifiez que le compte de service a été créé :
kubectl get serviceaccount -n rrsa-devSi la sortie inclut
dev-sa, le compte de service a été créé avec succès.
Étape 4 : Générer l'image du conteneur sidecar
Empaquetez KMS Agent en tant que conteneur sidecar pour le déployer aux côtés de votre application dans ACK.
-
Configurez les paramètres d'exécution de KMS Agent dans
config.toml.RemarqueLe fichier
config.tomlse trouve dans le répertoireconfigsdu code source alibabacloud-kms-agent obtenu à l'étape 1.[Server] HttpPort = 2025 [KMS] Region = "cn-hangzhou" [Cache] CacheType = "InMemory" CacheSize = 1000 TtlSeconds = 300 [Log] LogLevel = "Debug" LogPath = "./logs/" MaxSize = 100 MaxBackups = 2 -
Créez un
Dockerfile.Par exemple, créez un Dockerfile dans
deploy/ack/agentpour déployer l'agent. Pour le contenu du fichier, consultez agent_Dockerfile.# Use the centos image as the base FROM centos:centos7 # Set the working directory inside the container WORKDIR /usr/local/alibabacloudkmsagent # Copy the binary and config to the container COPY alibabacloud-kms-agent . COPY config.toml . # Set the entry point to run the kms agent ENTRYPOINT ["./alibabacloud-kms-agent", "agent", "./config.toml"] -
Copiez l'exécutable et la configuration dans le répertoire
deploy/ack/agent:deploy/ack/agent ├── alibabacloud-kms-agent ├── config.toml ├── Dockerfile.agent -
Générez l'image sidecar et poussez-la vers Container Registry :
# Build the image. docker build -t registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0 . # Push the image. docker push registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0
Étape 5 : Générer l'image du conteneur d'application
-
Pour une application déployée dans
deploy/ack/app, créez un Dockerfile dans ce répertoire :# Use the centos image as the base FROM centos:centos7 # Set the working directory inside the container WORKDIR / # Set the entry point to run the kms agent ENTRYPOINT ["sleep", "360000"] -
Générez l'image de l'application et poussez-la vers Container Registry :
# Build the image. docker build -t registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:app-v1.0 . # Push the image. docker push registry.cn-hangzhou.aliyuncs.com/<ns>/<repo>:app-v1.0
Étape 6 : Déployer l'application
Modèle de déploiement personnalisé
Définissez un Deployment personnalisé qui exécute KMS Agent en tant que sidecar aux côtés du conteneur d'application dans le même Pod. Pour plus d'informations sur l'exécution d'applications conteneurisées, consultez Créer un Deployment de charge de travail sans état.
KMS_TOKEN: Le chemin de stockage du fichier de jeton SSRF généré par l'agent au démarrage.ALIBABA_CLOUD_ROLE_ARN: L'ARN du rôle RAM.ALIBABA_CLOUD_OIDC_PROVIDER_ARN: L'ARN du fournisseur d'identité OIDC (l'ARN du cluster ACK).ALIBABA_CLOUD_OIDC_TOKEN_FILE: Le chemin du fichier contenant le jeton OIDC.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: rrsa-dev
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
serviceAccountName: dev-sa
containers:
- name: kmsagent
image: registry-vpc.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0
env:
- name: ALIBABA_CLOUD_ROLE_ARN
value: acs:ram::<uid>:role/dev-role-for-rrsa
- name: ALIBABA_CLOUD_OIDC_PROVIDER_ARN
value: acs:ram::<uid>:oidc-provider/ack-rrsa-<ackClusterId>
- name: ALIBABA_CLOUD_OIDC_TOKEN_FILE
value: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens/token
- name: KMS_TOKEN
value: file:///var/run/kmstoken/token
volumeMounts:
- name: shared-volume
mountPath: /var/run/kmstoken
- name: rrsa-oidc-token
mountPath: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens
readOnly: true
command: ["/bin/sh", "-c", "./alibabacloud-kms-agent token /var/run/kmstoken/token && ./alibabacloud-kms-agent agent config.toml"]
- name: my-app
image: registry-vpc.cn-hangzhou.aliyuncs.com/<ns>/<repo>:app-v1.0
volumeMounts:
- name: shared-volume
mountPath: /var/run/kmstoken
volumes:
- name: shared-volume
emptyDir: {}
- name: rrsa-oidc-token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
audience: sts.aliyuncs.com
expirationSeconds: 3600
path: token
Injection OpenKruise
OpenKruise est une extension Kubernetes standard qui gère efficacement les conteneurs d'application, les conteneurs sidecar et la distribution d'images. Pour plus d'informations, consultez Déployer une application cloud-native à l'aide d'OpenKruise.
-
Installez OpenKruise.
Connectez-vous à la console ACK. Dans le volet de navigation de gauche, cliquez sur Clusters.
Sur la page Clusters, cliquez sur le nom de votre cluster. Dans le volet de navigation de gauche, cliquez sur Components and Add-ons .
Sur la page Add-ons, cliquez sur l'onglet Manage Applications et recherchez ack-kruise.
Dans la colonne Actions, cliquez sur Install Now.
Sur la page Install Component, confirmez les informations du composant et cliquez sur OK.
-
Configurez la règle d'injection de sidecar.
Définissez un SidecarSet qui injecte le sidecar KMS Agent dans les Pods portant le libellé
app.-
Variables d'environnement :
KMS_TOKEN: Le chemin de stockage du fichier de jeton SSRF généré par l'agent au démarrage.ALIBABA_CLOUD_ROLE_ARN: L'ARN du rôle RAM.ALIBABA_CLOUD_OIDC_PROVIDER_ARN: L'ARN du fournisseur d'identité OIDC (l'ARN du cluster ACK).ALIBABA_CLOUD_OIDC_TOKEN_FILE: Le chemin du fichier contenant le jeton OIDC.
selector: sélectionne les Pods dans lesquels injecter le sidecar. Modifiez le sélecteur de libellé pour qu'il corresponde à votre application.
apiVersion: apps.kruise.io/v1alpha1 kind: SidecarSet metadata: name: kms-agent-sidecarset namespace: rrsa-dev spec: serviceAccountName: dev-sa containers: - name: kms-agent image: registry-vpc.cn-hangzhou.aliyuncs.com/<ns>/<repo>:kmsagent-v1.0 env: - name: ALIBABA_CLOUD_ROLE_ARN value: acs:ram::<uid>:role/dev-role-for-rrsa - name: ALIBABA_CLOUD_OIDC_PROVIDER_ARN value: acs:ram::<uid>:oidc-provider/ack-rrsa-<ackClusterId> - name: ALIBABA_CLOUD_OIDC_TOKEN_FILE value: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens/token - name: KMS_TOKEN value: file:///var/run/kmstoken/token volumeMounts: - name: shared-volume mountPath: /var/run/kmstoken - name: rrsa-oidc-token mountPath: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens readOnly: true command: ["/bin/sh", "-c", "./alibabacloud-kms-agent token /var/run/kmstoken/token && ./alibabacloud-kms-agent agent config.toml"] # Modify the selector to match your application Pods. selector: matchLabels: app: app volumes: - name: shared-volume emptyDir: {} - name: rrsa-oidc-token projected: defaultMode: 420 sources: - serviceAccountToken: audience: sts.aliyuncs.com expirationSeconds: 3600 path: token -
-
Déployez l'application avec injection automatique de KMS Agent.
Créez un Deployment avec le libellé
app: appafin que le sidecar soit automatiquement injecté.apiVersion: apps/v1 kind: Deployment metadata: name: app-with-kmsagent namespace: rrsa-dev spec: replicas: 1 selector: matchLabels: app: app template: metadata: labels: app: app spec: serviceAccountName: dev-sa containers: - name: my-app image: registry-vpc.cn-hangzhou.aliyuncs.com/<ns>/<repo>:app-v1.0 volumeMounts: - name: shared-volume mountPath: /var/run/kmstoken volumes: - name: shared-volume emptyDir: {} -
Exécutez votre application conteneurisée. Pour plus d'informations, consultez Créer un Deployment de charge de travail sans état.
Une fois l'application démarrée, le sidecar KMS Agent est injecté dans le Pod.
Sur la page Stateless, vous pouvez trouver un Deployment dont le nom commence par
ack-kms-agent. Le nombre de pods indique 2/2, ce qui signifie que le conteneur sidecar est injecté et fonctionne correctement.
Étape 7 : Créer et récupérer un secret
-
Créez un secret dans KMS.
Ajoutez le tag
env:devlors de la création du secret. Le conteneur d'application ne peut accéder qu'aux secrets portant ce tag.Connectez-vous à la console Key Management Service. Dans la barre de navigation supérieure, sélectionnez une région. Dans le volet de navigation de gauche, choisissez .
-
Cliquez sur l'onglet Generic Secrets, sélectionnez un Instance ID, puis cliquez sur Create Secret. Configurez les paramètres et cliquez sur OK.
Paramètre
Description
Secret Name
Un nom d'identifiant personnalisé. Doit être unique dans la région actuelle.
Secret Value
Sélectionnez Clé/Valeur du secret ou Texte brut et saisissez les données sensibles à stocker. La valeur doit avoir une longueur maximale de 30 720 octets (30 Ko).
Initial Version
Le numéro de version initial. Valeur par défaut : v1. Les valeurs personnalisées sont prises en charge.
CMK
Sélectionnez la clé symétrique utilisée pour chiffrer la valeur de l'identifiant. La clé et l'identifiant doivent appartenir à la même instance KMS.
ImportantLa clé et l'identifiant doivent appartenir à la même instance KMS, et la clé doit être une clé symétrique. Pour plus d'informations sur les clés symétriques prises en charge par KMS, consultez Types et spécifications de clés.
Si un utilisateur RAM ou un rôle RAM est utilisé, il doit disposer des autorisations nécessaires pour effectuer l'opération GenerateDataKey à l'aide de la clé maître de chiffrement.
Description
Une description facultative de l'identifiant pour l'identification et la gestion.
Définissez la stratégie d'accès pour l'identifiant afin de contrôler quels utilisateurs ou rôles RAM peuvent le lire ou le modifier.
Vous pouvez d'abord sélectionner la stratégie par défaut et la modifier ultérieurement selon vos besoins.
-
Récupérez la valeur du secret.
-
Utilisez la commande
curl:curl -v -H "X-KMS-Token:$(</var/run/kmstoken/token)" 'http://localhost:2025/secretsmanager/get?secretId=app/dev/secret-1' -
Récupérez le secret dans le code de votre application via une requête HTTP GET :
package main import ( "fmt" "io/ioutil" "net/http" ) func main() { url := fmt.Sprintf("http://localhost:2025/secretsmanager/get?secretId=%s", "app/dev/secret-1") token, err := ioutil.ReadFile("/var/run/kmstoken/token") if err != nil { fmt.Printf("error reading token file: %v\n", err) } req, err := http.NewRequest("GET", url, nil) if err != nil { fmt.Printf("error creating request: %v\n", err) } req.Header.Add("X-KMS-Token", string(token)) client := &http.Client{} resp, err := client.Do(req) if err != nil { fmt.Printf("error sending request: %v \n", err) } defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) fmt.Printf("status code %d - %s \n", resp.StatusCode, string(body)) }
-