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

Lecture de 9 minute(s)
0

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

Brève description

La propriété de balise de la ressource de l’instance EC2 ne s'étend pas aux volumes créés via CloudFormation. Le balisage peut restreindre le contrôle que vous avez sur vos instances. Le balisage vous aide à gérer les coûts de ressources spécifiques et à restreindre les politiques de gestion des identités et des accès (IAM) d'AWS. Le balisage vous permet également d'exercer un contrôle similaire sur d'autres ressources.

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

Remarque : Si vous recevez des erreurs lors de l'exécution des commandes de l'AWS CLI, assurez-vous que vous utilisez la version la plus récente de l'AWS CLI.

Résolution

Création d'une instance à l'aide d'un modèle CloudFormation

1.    Ouvrez la console CloudFormation.

2.    Choisissez Créer une pile, puis choisissez Modèle de conception.

3.    Dans l’onglet Paramètres de l’éditeur de code, choisissez Modèle.

4.    Pour Choisir la langue du modèle, choisissez YAML.

5.    Copiez l'un des modèles JSON ou YAML suivants, puis collez le modèle copié 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 you how to automatically tag the root volume of the EC2 instances that are created through the AWS 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 Availability 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",
                "try {\n",
                "$AWS_AVAIL_ZONE=(Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/placement/availability-zone' -UseBasicParsing).Content\n ",
                "$AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)\n ",
                "$AWS_INSTANCE_ID=(Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/instance-id' -UseBasicParsing).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",
                "}\n",
                "catch {\n",
                "Write-Output $PSItem\n",
                "}\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*"
                  ],
                  "Resource": "*"
                },
                {
                  "Effect": "Allow",
                  "Action": [
                    "ec2:CreateTags"
                  ],
                  "Resource": [
                    {
                      "Fn::Sub": "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:volume/*"
                    },
                    {
                      "Fn::Sub": "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/*"
                    }
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    "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 you how to automatically tag the root volume of the EC2
  instances that are created through the AWS 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 Availability 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: !Base64
        'Fn::Join':
          - ''
          - - |
              <powershell>
            - |
              try {
            - >-
              $AWS_AVAIL_ZONE=(Invoke-WebRequest -Uri
              'http://169.254.169.254/latest/meta-data/placement/availability-zone'
              -UseBasicParsing).Content

            - |-
              $AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)

            - >-
              $AWS_INSTANCE_ID=(Invoke-WebRequest -Uri
              'http://169.254.169.254/latest/meta-data/instance-id'
              -UseBasicParsing).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
            - |
              }
            - |
              catch {
            - |
              Write-Output $PSItem
            - |
              }
            - |
              </powershell>
      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: !Base64
        'Fn::Join':
          - ''
          - - |
              #!/bin/sh
            - >
              AWS_AVAIL_ZONE=$(curl
              http://169.254.169.254/latest/meta-data/placement/availability-zone)
            - |
              AWS_REGION=${AWS_AVAIL_ZONE::-1}
            - >
              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'
  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*'
                Resource: '*'
              - Effect: Allow
                Action:
                  - 'ec2:CreateTags'
                Resource:
                  - !Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:volume/*'
                  - !Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/*'
  InstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Path: /
      Roles:
        - !Ref InstanceRole

6.    Dans la section UserData du modèle, mettez à jour --tags Key=Name, Value=newAMI en fonction de vos exigences pour une instance Linux. Pour une instance Windows, mettez à jour $tag.key=« MyRootTag » et $tag.value=« MyRootVolumesValue ». Consultez les exemples suivants de la section UserData pour Linux et Windows.

Exemple 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 Windows :

#Windows UserData with standard Powershell commands (no AWS CLI installed)
    UserData:
    Fn::Base64: !Sub |
      <powershell>
      try {  
      $AWS_AVAIL_ZONE=(Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/placement/availability-zone' -UseBasicParsing).Content
      $AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)
      $AWS_INSTANCE_ID=(Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/instance-id' -UseBasicParsing).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
      }
      catch {
      Write-Output $PSItem
      }
      </powershell>

Important : Pour utiliser les commandes de l'interface de la ligne de commande AWS avec UserData, vous devez installer l'interface de la ligne de commande AWS au sein de 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 associer un profil d'instance à des instances EC2. Le profil d'instance inclut les autorisations permettant d'appeler les API ec2:DescribeInstances et ec2:CreateTags uniquement sur des volumes et des instances EC2 au sein de la région et du compte AWS.

7.    Cliquez sur l'icône Créer une pile.

8.    Dans le champ Nom de la pile, saisissez le nom de la pile.

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

10.    Choisissez Suivant.

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

12.    Pour permettre à la pile CloudFormation de créer une ressource IAM, cochez la case « Je reconnais qu'AWS CloudFormation est susceptible de créer des ressources IAM ».

13.    Choisissez Créer.

Marquer le volume racine des instances

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 CloudFormation pour confirmer que le volume a été balisé.


AWS OFFICIEL
AWS OFFICIELA mis à jour il y a 3 ans