Un auditeur signale le bucket d’artéfacts CodePipeline : chiffré au repos, mais avec la clé aws/s3 gérée par AWS par défaut. Le bucket contient 18 mois d’artéfacts de build — chaque commit, chaque exécution de test, chaque artéfact de déploiement — et l’audit veut soit la suppression du contenu plus ancien, des clés gérées par le client, ou une exception documentée. L’équipe veut des clés gérées par le client, mais la première tentative de bascule casse le pipeline parce que le bloc de confiance IAM sur la nouvelle clé manque de la condition kms:ViaService qui permet au rôle de service de CodePipeline d’utiliser la clé. Voici la configuration qui passe l’audit et garde le pipeline fonctionnel.
Ce qui se passe
Le magasin d’artéfacts CodePipeline a trois décisions de chiffrement indépendantes :
- Le chiffrement côté serveur du bucket S3. C’est défini au niveau du bucket — soit
SSE-S3(AES-256, gérée par AWS) soitSSE-KMS(chiffré KMS avec une clé gérée par AWS ou par le client). Pour les besoins d’audit, géré par le client est ce qui obtient la coche verte. - Le paramètre
EncryptionKeydu pipeline. C’est un champ séparé sur la définition du pipeline —ArtifactStore.EncryptionKeyréférence la clé KMS que CodePipeline utilisera pour chiffrer les métadonnées d’artéfact qu’il écrit dans S3. Par défaut, c’est la cléaws/s3gérée par AWS. - Accès multi-compte. Si le pipeline vit dans un compte AWS séparé de la cible de build ou de déploiement, la politique de clé KMS doit permettre au rôle multi-compte d’utiliser la clé — et la politique de bucket doit permettre au rôle multi-compte de lire/écrire.
Le mode d’échec d’audit que tout le monde rencontre est le troisième : le pipeline chiffre les artéfacts avec une clé gérée par le client dans le compte pipeline, mais l’étape de déploiement s’exécute dans un compte différent et le rôle de déploiement n’a pas kms:Decrypt sur la clé du compte pipeline. L’action de déploiement échoue avec AccessDenied, et la tentation est d’élargir la politique de clé avec Principal: '*' et kms:*, ce qui fait échouer l’audit suivant plus durement.
La bonne correction est une politique de clé spécifique avec une condition kms:ViaService restreignant l’accès multi-compte spécifiquement au service CodePipeline, plus une politique de bucket qui bloque tout upload non chiffré avec cette clé.
Comment vérifier
La clé gérée par le client, avec le bloc de confiance qui fonctionne et qui ne fonctionne pas :
Cassé (sur-privilégié) :
{
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::222222222222:root" },
"Action": "kms:*",
"Resource": "*"
}]
}
Ceci passe le smoke test (le multi-compte fonctionne) et échoue à l’audit (tout rôle dans le compte 222222222222 peut utiliser la clé pour n’importe quoi, y compris les déchiffrements S3 directs qui contournent CodePipeline).
Correct (moindre privilège avec kms:ViaService) :
{
"Statement": [
{
"Sid": "PipelineAccountRoot",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111111111111:root" },
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "DeployAccountCodePipelineOnly",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::222222222222:role/CrossAccountDeployRole" },
"Action": [
"kms:Decrypt",
"kms:DescribeKey",
"kms:GenerateDataKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "s3.ca-central-1.amazonaws.com"
},
"StringLike": {
"kms:EncryptionContext:aws:s3:arn": "arn:aws:s3:::pipeline-artifacts-ca-central-1/*"
}
}
}
]
}
La condition kms:ViaService force le principal multi-compte à utiliser la clé uniquement via S3 — les appels kms:Decrypt directs (comme une authentification de rôle fuitée essayant de lire le texte chiffré d’un artéfact téléchargé) échouent. La condition kms:EncryptionContext:aws:s3:arn restreint en outre spécifiquement au bucket d’artéfacts du pipeline, pas à n’importe quel bucket que le rôle de déploiement peut toucher.
La politique de bucket fait appliquer le chiffrement du côté stockage :
{
"Statement": [
{
"Sid": "DenyUnencryptedUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::pipeline-artifacts-ca-central-1/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
},
{
"Sid": "DenyWrongKey",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::pipeline-artifacts-ca-central-1/*",
"Condition": {
"StringNotLikeIfExists": {
"s3:x-amz-server-side-encryption-aws-kms-key-id": "arn:aws:kms:ca-central-1:111111111111:key/abc-123-def-456"
}
}
}
]
}
Les deux déclarations Deny ensemble signifient : chaque objet dans le bucket doit être chiffré KMS, et spécifiquement avec la bonne clé. Une tentative d’upload avec la clé aws/s3 gérée par AWS ou sans chiffrement échoue avant que l’objet n’atterrisse.
Vérifiez que le chiffrement au niveau du bucket est appliqué :
aws s3api get-bucket-encryption \
--bucket pipeline-artifacts-ca-central-1
La sortie attendue référence l’ARN de la clé gérée par le client, pas AES256.
Vérifiez que le pipeline référence la même clé :
aws codepipeline get-pipeline \
--name app-pipeline \
--query 'pipeline.artifactStore.encryptionKey'
Sortie attendue : {"id": "arn:aws:kms:ca-central-1:111111111111:key/abc-123-def-456", "type": "KMS"}.
Si l’encryptionKey du pipeline est null (ce qui est le défaut CloudFormation), CodePipeline utilise la clé gérée par AWS — et le Deny « mauvaise clé » de la politique de bucket bloquera la prochaine exécution du pipeline. Corrigez la définition du pipeline avant d’ajouter la politique de bucket.
La correction
La configuration du chiffrement des artéfacts, dans l’ordre :
-
Créez une clé KMS gérée par le client dans la région du pipeline. Étiquetez-la
purpose=codepipeline-artifacts. RéglezEnableKeyRotation: true— la rotation automatique annuelle est supportée pour les clés symétriques gérées par le client et est l’attente par défaut de l’audit. -
Écrivez la politique de clé avec
kms:ViaServicepour tout principal multi-compte. Le root du compte pipeline obtientkms:*(pour que les administrateurs puissent la gérer). Tout autre principal obtient unkms:Decrypt,kms:DescribeKey,kms:GenerateDataKeyrestreint avec la conditionkms:ViaService: s3.<region>.amazonaws.com. Sanskms:ViaService, la clé peut être utilisée directement pour le déchiffrement par quiconque akms:Decrypt— c’est la vulnérabilité que l’audit trouvera à la prochaine passe. -
Mettez à jour l’
ArtifactStore.EncryptionKeydu pipeline. Dans le CloudFormation, réglezEncryptionKey: { Id: !GetAtt ArtifactKey.Arn, Type: KMS }. Sans cela, CodePipeline écrit avec la clé par défaut et la nouvelle politique de bucket bloquera la prochaine exécution. -
Appliquez la politique de bucket. Les deux déclarations Deny font appliquer à la fois « doit être chiffré KMS » et « doit être la bonne clé KMS ». Appliquez dans cet ordre — si vous appliquez le Deny « mauvaise clé » en premier alors que le bucket a encore des objets chiffrés avec la mauvaise clé, les opérations de listing cassent.
-
Pour les déploiements multi-compte, accordez
kms:Decryptau rôle du compte de déploiement aveckms:ViaService. Le rôle du compte de déploiement assume depuis le rôle du compte pipeline, donc la chaîne de confiance est : rôle de service pipeline → rôle de déploiement multi-compte → S3 GetObject (qui appelle KMS Decrypt sous le capot). Chaque maillon a besoin de la bonne permission ; lekms:ViaServiceempêche le rôle de déploiement de pouvoir déchiffrer autre chose que via S3. -
Vérifiez les artéfacts existants. Les anciens artéfacts dans le bucket peuvent avoir été écrits avec la clé gérée par AWS. La politique de bucket refuse les nouveaux uploads avec la mauvaise clé, mais ne re-chiffre pas rétroactivement. Pour les besoins d’audit, soit supprimez les artéfacts plus anciens que la fenêtre de rétention (politique de cycle de vie S3) soit re-chiffrez-les avec
aws s3 cp s3://bucket/key s3://bucket/key --sse aws:kms --sse-kms-key-id <new-key>.
Trois règles qui tiennent à chaque engagement de chiffrement d’artéfact :
Clé gérée par le client, toujours, pour les pipelines de production. La clé aws/s3 gérée par AWS est bien pour les projets personnels, pas pour un SaaS qui fera face à une revue SOC 2 ou HIPAA.
kms:ViaService sur chaque accord multi-compte. Sans elle, une authentification de compte de déploiement fuitée devient un problème « lire tous les artéfacts de pipeline jamais ». Avec elle, l’authentification ne fonctionne que via S3, ce qui est ce que la conception vise.
La rotation de clé est automatique, pas manuelle. Activez la rotation au moment de la création de la clé. CodePipeline gère le re-chiffrement de manière transparente quand la clé tourne ; la rotation manuelle en production tend à trouver chaque endroit où l’ID de clé a été codé en dur que l’équipe avait oublié.
La passe d’audit est la partie facile une fois que la configuration est correcte. La partie difficile est d’obtenir le bloc de confiance correct la première fois.
Stack Harbor bâtit et opère les workflows CodePipeline en production dans le cadre de l’onboarding Gestion AWS et de la couche Pipeline de déploiement en continu. Si votre chemin de release passe encore par SSH et un message Slack, commencez par une consultation d’infrastructure.