Fn::GetStackOutput — Référencer les outputs CloudFormation entre comptes AWS
- Published on
- Authors

- Name
- Sylvain BRUAS
- @sylvain_bruas
Dans un article précédent sur le VPC partagé, nous avons mis en place une architecture où le compte réseau possède et gère le Amazon Virtual Private Cloud (VPC) — subnets, tables de routage, NAT Gateways, AWS Transit Gateway — et les autres comptes AWS (par équipe ou par projet) viennent y déployer leurs workloads en utilisant les subnets partagés via AWS Resource Access Manager (RAM).
Cette architecture est élégante du point de vue de la gouvernance, mais elle soulève immédiatement une question pratique : comment les templates AWS CloudFormation des équipes font-ils référence aux ressources du compte réseau ? Le VpcId, les SubnetId, les security groups de base — tout ça vit dans le compte réseau, dans une stack que l'équipe réseau maintient.
Jusqu'à très récemment, les options disponibles étaient toutes imparfaites : hard-coder les IDs (fragile), passer par AWS Systems Manager (SSM) Parameter Store (overhead opérationnel), ou utiliser Fn::ImportValue (limité au même compte et même région). AWS vient de changer la donne avec Fn::GetStackOutput, une nouvelle fonction intrinsèque qui résout exactement ce problème.
Le contexte : VPC partagé en multi-compte
Rappelons rapidement l'architecture cible décrite dans l'article sur le VPC partagé. L'organisation AWS est découpée en plusieurs comptes :
- Compte Réseau : propriétaire du VPC, des subnets, du Transit Gateway et de toute la couche réseau
- Comptes Équipes : chaque équipe (ou projet) a son propre compte AWS ; leurs ressources (Amazon Elastic Compute Cloud (EC2), AWS Lambda, Amazon Relational Database Service (RDS), Amazon Elastic Container Service (ECS)…) sont déployées dans les subnets partagés depuis le compte réseau
Le compte réseau déploie une stack NetworkStack qui contient toutes les ressources réseau et expose des Outputs (VpcId, SubnetIds, NatGatewayId…). Les comptes équipes veulent utiliser ces valeurs dans leurs propres stacks CloudFormation.
Le problème : référencer des ressources cross-compte avant Fn::GetStackOutput
Avant l'introduction de Fn::GetStackOutput, trois approches coexistaient, chacune avec ses limitations :
1. Hard-coding des IDs
La solution la plus simple et la plus dangereuse. On récupère les IDs manuellement et on les copie dans les templates ou dans des fichiers de paramètres.
# Avant — fragile et non reproductible
Parameters:
VpcId:
Type: String
Default: "vpc-0abc123def456789" # ← IDs en dur
SubnetPrivateA:
Type: String
Default: "subnet-0123456789abcdef0"
Le problème : si le compte réseau recrée le VPC (migration, incident, refactoring), tous les templates des équipes doivent être mis à jour manuellement. C'est une bombe à retardement.
2. SSM Parameter Store cross-compte
L'équipe réseau stocke les valeurs dans SSM, et les équipes consomment via des SSM dynamic references.
# Stack réseau — écriture dans SSM
VpcIdParam:
Type: AWS::SSM::Parameter
Properties:
Name: /network/vpc-id
Value: !Ref MyVpc
# Stack équipe — lecture depuis SSM cross-compte (impossible nativement)
VpcId: "{{resolve:ssm:/network/vpc-id}}" # ✗ ne fonctionne pas cross-compte
Les SSM dynamic references ne fonctionnent pas en cross-compte. L'équipe réseau devrait publier dans SSM dans chaque compte équipe, ce qui génère un overhead opérationnel considérable.
3. Fn::ImportValue — limité au même compte
Fn::ImportValue est la fonction native CloudFormation pour partager des outputs entre stacks. Elle crée une référence forte (le stack producteur ne peut pas être supprimé tant qu'une stack consommatrice existe), mais elle est strictement limitée au même compte et même région.
# ✗ Ne fonctionne pas cross-compte
VpcId: !ImportValue "NetworkStack-VpcId"
Aucune de ces approches ne résout proprement le cas du VPC partagé en multi-compte. C'est pour ça que Fn::GetStackOutput est une avancée significative.
Fn::GetStackOutput : la solution native
Fn::GetStackOutput est une fonction intrinsèque CloudFormation qui permet de référencer les outputs d'une autre stack, potentiellement dans un autre compte AWS ou une autre région. Elle résout la valeur au moment du déploiement (create ou update), en appelant l'API DescribeStacks de CloudFormation.
Syntaxe
La fonction accepte quatre paramètres :
| Paramètre | Obligatoire | Description |
|---|---|---|
StackName | Oui | Nom de la stack productrice |
OutputName | Oui | Identifiant logique de l'output (pas le nom d'export) |
Region | Non | Région AWS de la stack productrice |
RoleArn | Non | ARN du rôle IAM à assumer pour l'accès cross-compte |
Comment CloudFormation résout la valeur
Le mécanisme est simple : au moment du déploiement, CloudFormation assume le rôle AWS Identity and Access Management (IAM) spécifié dans le compte réseau, appelle cloudformation:DescribeStacks sur la NetworkStack, récupère la valeur de l'output demandé, et l'injecte dans le template en cours de déploiement.
Mise en pratique : templates CloudFormation
Stack productrice — compte réseau
L'équipe réseau déclare ses outputs normalement. Pas besoin de Export — c'est une différence importante avec Fn::ImportValue qui requiert un nom d'export.
# NetworkStack — compte réseau (111111111111)
AWSTemplateFormatVersion: '2010-09-09'
Description: Infrastructure réseau partagée
Resources:
SharedVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: "10.0.0.0/16"
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: shared-vpc-production
SubnetPrivateA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SharedVpc
CidrBlock: "10.0.1.0/24"
AvailabilityZone: !Select [0, !GetAZs ""]
SubnetPrivateB:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SharedVpc
CidrBlock: "10.0.2.0/24"
AvailabilityZone: !Select [1, !GetAZs ""]
SubnetPrivateC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref SharedVpc
CidrBlock: "10.0.3.0/24"
AvailabilityZone: !Select [2, !GetAZs ""]
Outputs:
VpcId:
Description: "ID du VPC partagé"
Value: !Ref SharedVpc
SubnetPrivateA:
Description: "Subnet privé — AZ A"
Value: !Ref SubnetPrivateA
SubnetPrivateB:
Description: "Subnet privé — AZ B"
Value: !Ref SubnetPrivateB
SubnetPrivateC:
Description: "Subnet privé — AZ C"
Value: !Ref SubnetPrivateC
Notez l'absence de bloc Export dans les outputs — Fn::GetStackOutput référence directement le nom logique de l'output (VpcId, SubnetPrivateA…), pas un nom d'export.
Stack consommatrice — compte équipe
# AppStack — compte équipe A (222222222222)
AWSTemplateFormatVersion: '2010-09-09'
Description: Application déployée dans le VPC partagé
Parameters:
NetworkAccountId:
Type: String
Default: "111111111111"
Resources:
AppSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "SG pour l'application"
VpcId:
Fn::GetStackOutput:
StackName: NetworkStack
OutputName: VpcId
RoleArn: !Sub "arn:aws:iam::${NetworkAccountId}:role/GetStackOutputRole"
AppLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Type: application
Subnets:
- Fn::GetStackOutput:
StackName: NetworkStack
OutputName: SubnetPrivateA
RoleArn: !Sub "arn:aws:iam::${NetworkAccountId}:role/GetStackOutputRole"
- Fn::GetStackOutput:
StackName: NetworkStack
OutputName: SubnetPrivateB
RoleArn: !Sub "arn:aws:iam::${NetworkAccountId}:role/GetStackOutputRole"
- Fn::GetStackOutput:
StackName: NetworkStack
OutputName: SubnetPrivateC
RoleArn: !Sub "arn:aws:iam::${NetworkAccountId}:role/GetStackOutputRole"
SecurityGroups:
- !Ref AppSecurityGroup
La syntaxe est identique pour chaque référence cross-compte. L'OutputName est exactement le nom déclaré dans le bloc Outputs de la stack réseau.
Configuration IAM : le rôle GetStackOutputRole
C'est la pièce centrale de la sécurité du dispositif. L'équipe réseau crée un rôle IAM dans son compte, que CloudFormation (depuis les comptes équipes) peut assumer pour lire les outputs.
Voici le template CloudFormation pour créer le rôle IAM dans le compte réseau :
# À déployer dans le compte réseau — peut faire partie de NetworkStack
GetStackOutputRole:
Type: AWS::IAM::Role
Properties:
RoleName: GetStackOutputRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS:
- "arn:aws:iam::222222222222:root" # Compte Équipe A
- "arn:aws:iam::333333333333:root" # Compte Équipe B
Action: sts:AssumeRole
Policies:
- PolicyName: DescribeNetworkStack
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- cloudformation:DescribeStacks
Resource:
- !Sub "arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/NetworkStack/*"
Points importants sur ce rôle :
- La permission
cloudformation:DescribeStacksest suffisante — pas besoin d'accès aux ressources réseau elles-mêmes - Le
Resourceest restreint àNetworkStackuniquement, pas à toutes les stacks du compte réseau - La trust policy liste explicitement les comptes autorisés — on peut affiner avec un
Principalpar rôle d'exécution CloudFormation plutôt que par compte (:root)
Référence forte vs référence faible
C'est la différence fondamentale entre Fn::ImportValue et Fn::GetStackOutput :
| Caractéristique | Fn::ImportValue | Fn::GetStackOutput |
|---|---|---|
| Portée | Même compte + même région | Cross-compte, cross-région |
| Nécessite un Export | Oui | Non |
| Type de référence | Forte | Faible |
| Suppression du stack producteur | Bloquée | Autorisée |
| Propagation automatique des changements | Non | Non |
Une référence faible signifie que si l'équipe réseau supprime ou recrée la NetworkStack, CloudFormation ne l'en empêchera pas. Les stacks consommatrices ne le sauront pas immédiatement — elles échoueront uniquement lors de leur prochain déploiement.
Pour compenser, deux mesures sont recommandées :
- Activer la protection contre la suppression sur
NetworkStack:
aws cloudformation update-termination-protection \
--enable-termination-protection \
--stack-name NetworkStack \
--region eu-west-1
- Documenter les dépendances dans les READMEs et les runbooks — les références
Fn::GetStackOutputn'apparaissent pas dans la console CloudFormation du compte réseau.
Intégration avec AWS CDK
AWS Cloud Development Kit (CDK) supporte nativement Fn::GetStackOutput pour les références cross-compte et cross-région. Avec la clé de contexte @aws-cdk/core:defaultCrossStackReferences :
strong(défaut) : utiliseFn::ImportValuepour les références dans le même compte/régionweak: utilise toujoursFn::GetStackOutputboth: génère les deux types simultanément (migration progressive)
Pour notre architecture SharedVPC, le comportement weak est le bon choix : on est obligatoirement en cross-compte.
// cdk.json
{
"context": {
"@aws-cdk/core:defaultCrossStackReferences": "weak"
}
}
Ce qu'il faut retenir
Fn::GetStackOutputpermet de référencer les outputs d'une stack CloudFormation dans n'importe quel compte AWS et n'importe quelle région, sans avoir besoin d'un nom d'export- Pour le pattern VPC partagé, c'est la solution idéale : l'équipe réseau expose ses outputs (VpcId, SubnetIds…), les équipes applicatives les consomment directement depuis leurs stacks
- La résolution se fait au moment du déploiement via
cloudformation:DescribeStacks— un rôle IAM dans le compte réseau est nécessaire pour les accès cross-compte - La référence est faible (pas de blocage de suppression) — compensez avec la protection contre la suppression sur la
NetworkStacket une documentation explicite des dépendances - La valeur est figée au moment du déploiement. Si l'équipe réseau modifie un output, les stacks consommatrices doivent être mises à jour explicitement pour récupérer la nouvelle valeur
Fn::GetStackOutput ne remplace pas Fn::ImportValue pour les cas dans le même compte — la référence forte garde tout son intérêt quand on veut une garantie d'intégrité référentielle. Mais pour le cross-compte, c'est désormais l'option native et la plus propre.



