【问题标题】:Mandatory tagging when launching EC2 instance启动 EC2 实例时强制标记
【发布时间】:2015-10-30 07:30:03
【问题描述】:

在 AWS 中,有没有办法强制 IAM 用户标记他/她即将启动的实例?价值是多少并不重要。我想确保它被正确标记,以便可以正确识别长时间运行的实例并通知所有者。目前标记是可选的。

我目前所做的是使用 CloudTrail 并通过其 IAM 用户识别实例。我不喜欢它,因为定期运行脚本是一项额外的工作,而且 CloudTrail 只有 7 天的数据。如果 AWS 有所有者的实例属性就好了。

在我们的案例中,使用密钥对来识别所有者并不是一个可行的解决方案。以前有人遇到过这个问题,您是如何解决的?

【问题讨论】:

    标签: amazon-web-services amazon-ec2


    【解决方案1】:

    一种方法:不要授予他们启动框的 IAM 权限。相反,有一个允许他们这样做的网络服务。 (无论如何,生产应该是完全自动化的)。当他们使用您的服务时,您可以执行所有您想要的规则。是的,这是一项相当多的工作,所以并不适合所有人。

    目前标记是可选的。

    比这更糟糕。标记需要第二次 API 调用,因此即使使用 API,由于打嗝,事情也可以在没有标记的情况下启动。

    【讨论】:

    • 仅供参考,您现在可以在创建资源的同一个调用中应用标签(请参阅aws.amazon.com/blogs/aws/…)。因此,您现在可以使用策略来强制使用标签。
    【解决方案2】:

    我使用 AWS Lambda 解决了这个问题。当 CloudTrail 在 S3 中创建对象时,它会触发一个导致 Lambda 函数执行的事件。然后 Lambda 函数解析 S3 对象并创建标签。有大约 2 分钟的延迟,但该解决方案完美运行。

    【讨论】:

    • 等等...您在问题中从未提到过 Lambda 或 S3。这如何解决您的问题?
    • @Julian 因为当我发布问题时,我不知道这可以通过使用 Lambda 来解决。在我的问题中,我提到了使用 Cloudtrail 日志。 Cloudtrail 将活动保存在已知的 S3 存储桶中。唯一缺少的部分是 Lambda,它会在 CloudTrail 记录 RunInstance API 后立即标记实例。
    • 我明白了。我必须说一个非常聪明的解决方案!干杯!
    【解决方案3】:

    正如@helloV 所提到的,这可以通过使用 AWS CloudTrail 日志(一旦正确启用)和 AWS Lambda 来实现。我可以通过在 python Lambda 函数中运行以下代码来完成此操作:

    s3 = boto3.client('s3')
    ec2 = boto3.client(service_name='ec2', aws_access_key_id=aws_key, aws_secret_access_key=aws_secret_key)
    
    def lambda_handler(event, context):
    
        # Get the object from the event and show its content type
        bucket = event['Records'][0]['s3']['bucket']['name']
        key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
    
        try:
            response = s3.get_object(Bucket=bucket, Key=key)
            compressed_file = StringIO.StringIO()
            compressed_file.write(response['Body'].read())
            compressed_file.seek(0)
            decompressed_file = gzip.GzipFile(fileobj=compressed_file, mode='rb')
    
            successful_tags = 0;
            json_data = json.load(decompressed_file)
            for record in json_data['Records']:
                if record['eventName'] == 'RunInstances':
                    instance_user = record['userIdentity']['userName']
                    instances_set = record['responseElements']['instancesSet']
                    for instance in instances_set['items']:
                        instance_id = instance['instanceId']
                        ec2.create_tags(Resources=[instance_id], Tags=[{'Key':'Owner', 'Value':instance_user}])
                        successful_tags += 1
            return 'Tagged ' + str(successful_tags) + ' instances successfully'
        except Exception as e:
            print(e)
            print('Error tagging object {} from bucket {}'.format(key, bucket))
            raise e
    

    【讨论】:

      【解决方案4】:

      查看 capitalone.io/cloud-custodian 开源项目——它有能力执行这样的政策

      【讨论】:

        【解决方案5】:
        {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Sid": "GrantIAMPassRoleOnlyForEC2",
                    "Action": [
                        "iam:PassRole"
                    ],
                    "Effect": "Allow",
                    "Resource": [
                        "arn:aws:iam::*:role/ec2tagrestricted",
                        "arn:aws:iam::*:role/ec2tagrestricted"
                    ],
                    "Condition": {
                        "StringEquals": {
                            "iam:PassedToService": "ec2.amazonaws.com"
                        }
                    }
                },
                {
                    "Sid": "ReadOnlyEC2WithNonResource",
                    "Action": [
                        "ec2:Describe*",
                        "iam:ListInstanceProfiles"
                    ],
                    "Effect": "Allow",
                    "Resource": "*"
                },
                {
                    "Sid": "ModifyingEC2WithNonResource",
                    "Action": [
                        "ec2:CreateKeyPair",
                        "ec2:CreateSecurityGroup"
                    ],
                    "Effect": "Allow",
                    "Resource": "*"
                },
                {
                    "Sid": "RunInstancesWithTagRestrictions",
                    "Effect": "Allow",
                    "Action": "ec2:RunInstances",
                    "Resource": [
                        "arn:aws:ec2:us-east-1:*:instance/*",
                        "arn:aws:ec2:us-east-1:*:volume/*"
                    ],
                    "Condition": {
                        "StringEquals": {
                            "aws:RequestTag/test": "${aws:userid}"
                        }
                    }
                },
                {
                    "Sid": "RemainingRunInstancePermissionsNonResource",
                    "Effect": "Allow",
                    "Action": "ec2:RunInstances",
                    "Resource": [
                        "arn:aws:ec2:us-east-1::image/*",
                        "arn:aws:ec2:us-east-1::snapshot/*",
                        "arn:aws:ec2:us-east-1:*:network-interface/*",
                        "arn:aws:ec2:us-east-1:*:key-pair/*",
                        "arn:aws:ec2:us-east-1:*:security-group/*"
                    ]
                },
                {
                    "Sid": "EC2RunInstancesVpcSubnet",
                    "Effect": "Allow",
                    "Action": "ec2:RunInstances",
                    "Resource": "arn:aws:ec2:us-east-1:*:subnet/*",
                    "Condition": {
                        "StringEquals": {
                            "ec2:Vpc": "arn:aws:ec2:us-east-1:*:vpc/vpc-8311b8f9"
                        }
                    }
                },
                {
                    "Sid": "EC2VpcNonResourceSpecificActions",
                    "Effect": "Allow",
                    "Action": [
                        "ec2:DeleteNetworkAcl",
                        "ec2:DeleteNetworkAclEntry",
                        "ec2:DeleteRoute",
                        "ec2:DeleteRouteTable",
                        "ec2:AuthorizeSecurityGroupEgress",
                        "ec2:AuthorizeSecurityGroupIngress",
                        "ec2:RevokeSecurityGroupEgress",
                        "ec2:RevokeSecurityGroupIngress",
                        "ec2:DeleteSecurityGroup",
                        "ec2:CreateNetworkInterfacePermission",
                        "ec2:CreateRoute",
                        "ec2:UpdateSecurityGroupRuleDescriptionsEgress",
                        "ec2:UpdateSecurityGroupRuleDescriptionsIngress"
                    ],
                    "Resource": "*",
                    "Condition": {
                        "StringEquals": {
                            "ec2:Vpc": "arn:aws:ec2:us-east-1:*:vpc/vpc-8311b8f9"
                        }
                    }
                },
                {
                    "Sid": "AllowInstanceActionsTagBased",
                    "Effect": "Allow",
                    "Action": [
                        "ec2:RebootInstances",
                        "ec2:StopInstances",
                        "ec2:TerminateInstances",
                        "ec2:StartInstances",
                        "ec2:AttachVolume",
                        "ec2:DetachVolume",
                        "ec2:AssociateIamInstanceProfile",
                        "ec2:DisassociateIamInstanceProfile",
                        "ec2:GetConsoleScreenshot",
                        "ec2:ReplaceIamInstanceProfileAssociation"
                    ],
                    "Resource": [
                        "arn:aws:ec2:us-east-1:347612567792:instance/*",
                        "arn:aws:ec2:us-east-1:347612567792:volume/*"
                    ],
                    "Condition": {
                        "StringEquals": {
                            "ec2:ResourceTag/test": "${aws:userid}"
                        }
                    }
                },
                {
                    "Sid": "AllowCreateTagsOnlyLaunching",
                    "Effect": "Allow",
                    "Action": [
                        "ec2:CreateTags"
                    ],
                    "Resource": [
                        "arn:aws:ec2:us-east-1:347612567792:instance/*",
                        "arn:aws:ec2:us-east-1:347612567792:volume/*"
                    ],
                    "Condition": {
                        "StringEquals": {
                            "ec2:CreateAction": "RunInstances"
                        }
                    }
                }
            ]
        }
        

        此策略限制用户仅在标签键为 test 且值为变量 ${aws.userid} 时才能启动 ec2 实例,可以找到不同的值 here 值得注意的事情

        • 这不会限制用户可以启动的 ec2 实例的数量
        • 用户可以更改现有实例标签的标签并获得控制权

        我们可以使用 TagKeys https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html#access_tags_control-tag-keys 来解决以上两种情况但我没有这样做

        【讨论】:

          【解决方案6】:

          将此策略附加到用户或组,以防止他们在未标记实例的情况下启动实例:

          {
              "Version": "2012-10-17",
              "Statement": {
                  "Effect": "Deny",
                  "Action": "ec2:RunInstances",
                  "Resource": "*",
                  "Condition": {
                      "Null": {
                          "aws:RequestTag/Owner": "true"
                      }
                  }
              }
          }
          

          当用户尝试启动实例时,他们会收到错误:

          (如果有人知道如何显示更清晰的错误消息,请在 cmets 中告诉我们。)

          像这样解码错误:

          aws sts decode-authorization-message \
            --encoded-message <encoded-message> \
            --query DecodedMessage --output text | jq '.'
          

          部分(巨)响应如下:

          {
            "allowed": false,
            "explicitDeny": true,
            "matchedStatements": {
              "items": [
                {
                  "statementId": "",
                  "effect": "DENY",
                  "principals": {
                    "items": [
                      {
                        "value": "AIDATDOMLI3YFAYEBFGSO"
                      }
                    ]
                  },
                  "principalGroups": {
                    "items": []
                  },
                  "actions": {
                    "items": [
                      {
                        "value": "ec2:RunInstances"
                      }
                    ]
                  },
                  "resources": {
                    "items": [
                      {
                        "value": "*"
                      }
                    ]
                  },
                  "conditions": {
                    "items": [
                      {
                        "key": "aws:RequestTag/Owner",
                        "values": {
                          "items": [
                            {
                              "value": "true"
                            }
                          ]
                        }
                      }
                    ]
                  }
                }
              ]
            }
          }
          

          显示启动失败,因为缺少Owner标签。

          【讨论】:

            【解决方案7】:

            您是否在启动时使用/需要用户数据脚本?我们使用该脚本进程在每个实例启动时对其进行正确标记。

            我们将支持脚本刻录到由 userdata 启动的 AMI 中,并解析命令行参数。然后使用这些参数为新启动的实例创建标签。

            对于手动启动,用户必须加载正确的用户数据脚本才能工作。但是从自动启动脚本,或从 Auto-scaling Group 中正确配置的启动配置,它可以完美运行。

            <script>
            PowerShell -ExecutionPolicy Bypass -NoProfile -File c:\tools\server_userdata.ps1  -function Admin -environment production
            </script>
            

            使用此方法,使用该用户数据启动的实例将自动使用 Function 和 Environment 标记。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-03-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-04-02
              相关资源
              最近更新 更多