Comment puis-je baliser un volume racine à partir d'une instance créée par AWS CloudFormation ?

Date de la dernière mise à jour : 16/01/2020

Je voudrais baliser le volume racine de mes instances Amazon Elastic Compute Cloud (Amazon EC2) créées via AWS CloudFormation.

Brève description

La propriété de balise de la ressource d'instance Amazon EC2 ne s'étend pas aux volumes qui sont créés via AWS CloudFormation. Le balisage peut limiter le contrôle dont vous disposez sur vos instances. Cela vous aide à gérer les coûts des ressources spécifiques, à restreindre les stratégies AWS Identity and Access Management (IAM) et à exercer un contrôle similaire sur les autres ressources.

L'amorçage avec AWS CloudFormation vous permet de baliser le volume racine Amazon Elastic Block Store (Amazon EBS) de votre instance. La méthode d'amorçage est effectuée par le biais de la propriété UserData de la ressource AWS::EC2::Instance. Pour effectuer l'amorçage, utilisez les commandes de l'interface de ligne de commande AWS (AWS CLI) ou les commandes PowerShell standard après avoir créé votre instance.

Résolution

Créer une instance avec un modèle AWS CloudFormation

1.    Ouvrez la console AWS CloudFormation.

2.    Choisissez Create Stack (Créer une pile), puis Concevoir un modèle.

3.    Dans l'éditeur de code, sur l'onglet Paramètres, choisissez Modèles.

4.    Pour Choose template language (Choisir la langue du modèle), choisissez YAML.

5.    Copiez le modèle JSON ou YAML suivant, puis collez le modèle dans votre éditeur de code.

Modèle JSON :

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "AWS CloudFormation Sample Template Tagging Root Volumes of EC2 Instances: This template shows how to automatically tag the root volume of the EC2 instances which are created through the CloudFormation template. This is done through the UserData property of the AWS::EC2::Instance resource. **WARNING** This template creates two Amazon EC2 instances and an IAM Role. You will be billed for the AWS resources used if you create a stack from this template.",
  "Parameters": {
    "KeyName": {
      "Type": "AWS::EC2::KeyPair::KeyName",
      "Description": "Name of an existing EC2 KeyPair to enable SSH access to the ECS instances."
    },
    "InstanceType": {
      "Description": "EC2 instance type",
      "Type": "String",
      "Default": "t2.micro",
      "AllowedValues": [
        "t2.micro",
        "t2.small",
        "t2.medium",
        "t2.large",
        "m3.medium",
        "m3.large",
        "m3.xlarge",
        "m3.2xlarge",
        "m4.large",
        "m4.xlarge",
        "m4.2xlarge",
        "m4.4xlarge",
        "m4.10xlarge",
        "c4.large",
        "c4.xlarge",
        "c4.2xlarge",
        "c4.4xlarge",
        "c4.8xlarge",
        "c3.large",
        "c3.xlarge",
        "c3.2xlarge",
        "c3.4xlarge",
        "c3.8xlarge",
        "r3.large",
        "r3.xlarge",
        "r3.2xlarge",
        "r3.4xlarge",
        "r3.8xlarge",
        "i2.xlarge",
        "i2.2xlarge",
        "i2.4xlarge",
        "i2.8xlarge"
      ],
      "ConstraintDescription": "Please choose a valid instance type."
    },
    "InstanceAZ": {
      "Description": "EC2 AZ.",
      "Type": "AWS::EC2::AvailabilityZone::Name",
      "ConstraintDescription": "Must be the name of an availabity zone."
    },
    "WindowsAMIID": {
      "Description": "The Latest Windows 2016 AMI taken from the public Systems Manager Parameter Store",
      "Type": "AWS::SSM::Parameter::Value<String>",
      "Default": "/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base"
    },
    "LinuxAMIID": {
      "Description": "The Latest Amazon Linux 2 AMI taken from the public Systems Manager Parameter Store",
      "Type": "AWS::SSM::Parameter::Value<String>",
      "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
    }
  },
  "Resources": {
    "WindowsInstance": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "ImageId": {
          "Ref": "WindowsAMIID"
        },
        "InstanceType": {
          "Ref": "InstanceType"
        },
        "AvailabilityZone": {
          "Ref": "InstanceAZ"
        },
        "IamInstanceProfile": {
          "Ref": "InstanceProfile"
        },
        "KeyName": {
          "Ref": "KeyName"
        },
        "UserData": {
          "Fn::Base64": {
            "Fn::Join" : [
              "",
              [
                "<powershell>\n",
                "$AWS_AVAIL_ZONE=(curl http://169.254.169.254/latest/meta-data/placement/availability-zone).Content\n ",
                "$AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)\n ",
                "$AWS_INSTANCE_ID=(curl http://169.254.169.254/latest/meta-data/instance-id).Content\n ",
                "$ROOT_VOLUME_IDS=((Get-EC2Instance -Region $AWS_REGION -InstanceId $AWS_INSTANCE_ID).Instances.BlockDeviceMappings | where-object DeviceName -match '/dev/sda1').Ebs.VolumeId\n ",
                "$tag = New-Object Amazon.EC2.Model.Tag\n ",
                "$tag.key = \"MyRootTag\"\n ",
                "$tag.value = \"MyRootVolumesValue\"\n ",
                "New-EC2Tag -Resource $ROOT_VOLUME_IDS -Region $AWS_REGION -Tag $tag\n",
                "</powershell>\n"
              ]
            ]
          }
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Ref": "AWS::StackName"
            }
          }
        ],
        "BlockDeviceMappings": [
          {
            "DeviceName": "/dev/sdm",
            "Ebs": {
              "VolumeType": "io1",
              "Iops": "200",
              "DeleteOnTermination": "true",
              "VolumeSize": "10"
            }
          }
        ]
      }
    },
    "LinuxInstance": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "ImageId": {
          "Ref": "LinuxAMIID"
        },
        "InstanceType": {
          "Ref": "InstanceType"
        },
        "AvailabilityZone": {
          "Ref": "InstanceAZ"
        },
        "IamInstanceProfile": {
          "Ref": "InstanceProfile"
        },
        "KeyName": {
          "Ref": "KeyName"
        },
        "UserData": {
          "Fn::Base64": {
            "Fn::Join" : [
              "",
              [
                "#!/bin/sh\n",
                "AWS_AVAIL_ZONE=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)\n",
                "AWS_REGION=${AWS_AVAIL_ZONE::-1}\n",
                "AWS_INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)\n",
                "ROOT_VOLUME_IDS=$(aws ec2 describe-instances --region $AWS_REGION --instance-id $AWS_INSTANCE_ID --output text --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId)\n",
                "aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=MyRootTag,Value=MyRootVolumesValue\n"
              ]
            ]
          }
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Ref": "AWS::StackName"
            }
          }
        ],
        "BlockDeviceMappings": [
          {
            "DeviceName": "/dev/sdm",
            "Ebs": {
              "VolumeType": "io1",
              "Iops": "200",
              "DeleteOnTermination": "true",
              "VolumeSize": "10"
            }
          }
        ]
      }
    },
    "InstanceRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "ec2.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path": "/",
        "Policies": [
          {
            "PolicyName": "taginstancepolicy",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "ec2:Describe*",
                    "ec2:CreateTags"
                  ],
                  "Resource": "*"
                }
              ]
            }
          }
        ]
      }
    },
    "InstanceProfile": {
      "Type": "AWS::IAM::InstanceProfile",
      "Properties": {
        "Path": "/",
        "Roles": [
          {
            "Ref": "InstanceRole"
          }
        ]
      }
    }
  }
}

Modèle YAML :

AWSTemplateFormatVersion: 2010-09-09
Description: 'AWS CloudFormation Sample Template Tagging Root Volumes of EC2 Instances:
 This template shows how to automatically tag the root volume of the EC2 instances which are
 created through the CloudFormation template. This is done through the UserData property of 
 the AWS::EC2::Instance resource.
 **WARNING** This template creates two Amazon EC2 instances and an IAM Role.
 You will be billed for the AWS resources used if you create a stack from this template.'
Parameters:
 KeyName:
  Type: AWS::EC2::KeyPair::KeyName
  Description: Name of an existing EC2 KeyPair to enable SSH access to the ECS instances.
 InstanceType:
  Description: EC2 instance type
  Type: String
  Default: t2.micro
  AllowedValues: [t2.micro, t2.small, t2.medium, t2.large, m3.medium, m3.large,
   m3.xlarge, m3.2xlarge, m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m4.10xlarge,
   c4.large, c4.xlarge, c4.2xlarge, c4.4xlarge, c4.8xlarge, c3.large, c3.xlarge,
   c3.2xlarge, c3.4xlarge, c3.8xlarge, r3.large, r3.xlarge, r3.2xlarge, r3.4xlarge,
   r3.8xlarge, i2.xlarge, i2.2xlarge, i2.4xlarge, i2.8xlarge]
  ConstraintDescription: Please choose a valid instance type.
 InstanceAZ:
  Description: EC2 AZ.
  Type: AWS::EC2::AvailabilityZone::Name
  ConstraintDescription: "Must be the name of an availabity zone."
 WindowsAMIID:
  Description: The Latest Windows 2016 AMI taken from the public Systems Manager Parameter Store
  Type: AWS::SSM::Parameter::Value<String>
  Default: /aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base
 LinuxAMIID:
  Description: The Latest Amazon Linux 2 AMI taken from the public Systems Manager Parameter Store
  Type : AWS::SSM::Parameter::Value<String>
  Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Resources:
 #Tagging the root volume for the EC2 instances with the Windows OS
 #The commented out powershell commands are to utilize if the AMI has the AWS CLI installed and you prefer that approach.
 WindowsInstance:
  Type: 'AWS::EC2::Instance'
  Properties:
   ImageId: !Ref WindowsAMIID
   InstanceType: !Ref InstanceType
   AvailabilityZone: !Ref InstanceAZ
   IamInstanceProfile: !Ref InstanceProfile
   KeyName: !Ref KeyName
   UserData: 
    Fn::Base64: |
     <powershell>
      $AWS_AVAIL_ZONE=(curl http://169.254.169.254/latest/meta-data/placement/availability-zone).Content
      $AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)
      $AWS_INSTANCE_ID=(curl http://169.254.169.254/latest/meta-data/instance-id).Content
      $ROOT_VOLUME_IDS=((Get-EC2Instance -Region $AWS_REGION -InstanceId $AWS_INSTANCE_ID).Instances.BlockDeviceMappings | where-object DeviceName -match '/dev/sda1').Ebs.VolumeId
      $tag = New-Object Amazon.EC2.Model.Tag
      $tag.key = "MyRootTag"
      $tag.value = "MyRootVolumesValue"
      New-EC2Tag -Resource $ROOT_VOLUME_IDS -Region $AWS_REGION -Tag $tag
     </powershell>
    #<powershell>
    #$AWS_AVAIL_ZONE=(curl http://169.254.169.254/latest/meta-data/placement/availability-zone).Content
    #$AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)
    #$AWS_INSTANCE_ID=(curl http://169.254.169.254/latest/meta-data/instance-id).Content
    #$ROOT_VOLUME_IDS =(aws ec2 describe-instances --region eu-west-1 --instance-id $AWS_INSTANCE_ID --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId)
    #aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=MyRootTag,Value=MyRootVolumesValue
    #</powershell>
   Tags:
    - Key: Name
     Value: !Ref 'AWS::StackName'
   BlockDeviceMappings:
    - DeviceName: /dev/sdm
     Ebs:
      VolumeType: io1
      Iops: '200'
      DeleteOnTermination: 'true'
      VolumeSize: '10'
 #Tagging the root volume for EC2 instances with an Unix OS with the AWS CLI installed.
 LinuxInstance:
  Type: 'AWS::EC2::Instance'
  Properties:
   ImageId: !Ref LinuxAMIID
   InstanceType: !Ref InstanceType
   AvailabilityZone: !Ref InstanceAZ
   IamInstanceProfile: !Ref InstanceProfile
   KeyName: !Ref KeyName
   UserData: 
    Fn::Base64: |
     #!/bin/sh
     AWS_AVAIL_ZONE=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)
     AWS_REGION="`echo \"$AWS_AVAIL_ZONE\" | sed 's/[a-z]$//'`"
     AWS_INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)
     ROOT_VOLUME_IDS=$(aws ec2 describe-instances --region $AWS_REGION --instance-id $AWS_INSTANCE_ID --output text --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId)
     aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=MyRootTag,Value=MyRootVolumesValue
   Tags:
    - Key: Name
     Value: !Ref 'AWS::StackName'
   BlockDeviceMappings:
    - DeviceName: /dev/sdm
     Ebs:
      VolumeType: io1
      Iops: '200'
      DeleteOnTermination: 'true'
      VolumeSize: '10'
 #AMI role given to the instances, the instances need the describe and create tags to complete the UserData
 InstanceRole:
  Type: 'AWS::IAM::Role'
  Properties:
   AssumeRolePolicyDocument:
    Version: 2012-10-17
    Statement:
     - Effect: Allow
      Principal:
       Service:
        - ec2.amazonaws.com
      Action:
       - 'sts:AssumeRole'
   Path: /
   Policies:
    - PolicyName: taginstancepolicy
     PolicyDocument:
      Version: 2012-10-17
      Statement:
       - Effect: Allow
        Action:
         - 'ec2:Describe*'
         - 'ec2:CreateTags'
        Resource: '*'
 InstanceProfile:
  Type: 'AWS::IAM::InstanceProfile'
  Properties:
   Path: /
   Roles:
    - !Ref InstanceRole

6.    Dans la section du modèle UserData, mettez à jour --tags Key=Name,Value=newAMI afin de correspondre à vos besoins en matière d'instance Linux. Dans le cas d'une instance Windows, mettez à jour $tag.key="MyRootTag" et $tag.value="MyRootVolumesValue". Consultez les exemples de section UserData suivants pour Linux et Windows.

Exemple pour Linux :

#Linux UserData
    UserData:
       Fn::Base64: !Sub |
          #!/bin/bash
          AWS_AVAIL_ZONE=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)
          AWS_REGION="`echo \"$AWS_AVAIL_ZONE\" | sed 's/[a-z]$//'`"
          AWS_INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)
          ROOT_VOLUME_IDS=$(aws ec2 describe-instances --region $AWS_REGION --instance-id $AWS_INSTANCE_ID --output text --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId)
          aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=MyRootTag,Value=MyRootVolumesValue

Exemple pour Windows :

#Windows UserData with standard Powershell commands (no AWS CLI installed)
      UserData:
         Fn::Base64: !Sub |
          <powershell>
            $AWS_AVAIL_ZONE=(curl http://169.254.169.254/latest/meta-data/placement/availability-zone).Content
            $AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)
            $AWS_INSTANCE_ID=(curl http://169.254.169.254/latest/meta-data/instance-id).Content
            $ROOT_VOLUME_IDS=((Get-EC2Instance -Region $AWS_REGION -InstanceId $AWS_INSTANCE_ID).Instances.BlockDeviceMappings | where-object DeviceName -match '/dev/sda1').Ebs.VolumeId
            $tag = New-Object Amazon.EC2.Model.Tag
            $tag.key = "MyRootTag"
            $tag.value = "MyRootVolumesValue"
            New-EC2Tag -Resource $ROOT_VOLUME_IDS -Region $AWS_REGION -Tag $tag
          </powershell>

Remarque : pour que UserData utilise les commandes de l'interface de ligne de commande AWS, vous devez installer l'interface de ligne de commande AWS dans l'Amazon Machine Image (AMI) de vos instances EC2. L'interface de ligne de commande AWS est installée par défaut sur toutes les AMI Amazon Linux. Vous devez également attacher un profil d'instance à vos instances EC2. Le profil d'instance inclut les autorisations pour appeler les API ec2:DescribeInstances et ec2:CreateTags.

7.    Choisissez l'icône Create Stack (Créer une pile).

8.    Pour Stack name (Nom de la pile), saisissez un nom à donner à votre pile.

9.    Dans la section Paramètres, entrez les informations appropriées en fonction des besoins de votre environnement, y compris votre type d'instance, la paire de clés EC2 et l'AMI.

10.    Sélectionnez Suivant.

11.    Dans la section Options, entrez les informations appropriées pour votre pile, puis sélectionnez Suivant.

12.    Pour activer la pile AWS CloudFormation afin de créer une ressource IAM, cochez la case « Je comprends qu'AWS CloudFormation peut créer des ressources IAM ».

13.    Sélectionnez Créer.

Baliser le volume racine de l'instance

1.    Ouvrez la console Amazon EC2.

2.    Dans le volet de navigation, dans la section Elastic Block Store, choisissez Volumes.

3.    Dans le champ Filtre, entrez la balise que vous avez définie dans la pile AWS CloudFormation afin de confirmer que le volume a été balisé.


Cet article vous a-t-il été utile ?

Cette page peut-elle être améliorée ?


Vous avez besoin d’aide ?