Как я могу (безопасно) загрузить частный актив S3 на новый экземпляр EC2 с облачным?
Я использую CloudFormation для управления стеком веб-серверов Tomcat, но я устал от выполнения управления AMI для новых версий приложений. Я бы хотел двигаться в направлении шеф-повара, но сейчас у меня нет времени. Вместо этого я пытаюсь покорить простую проблему с созданием веб-сервера: как загрузить "текущую" WAR при росте новых машин?
Моя мысль заключалась в использовании частного ведра S3 и cloudinit, но я немного озадачен тем, что делать с учетными данными IAM. Я мог бы помещать их в пользовательские данные шаблона, но я не хочу этого делать, особенно потому, что я контролирую этот файл. Единственная альтернатива, которую я могу придумать, - это использовать переменные среды в AMI. Они должны быть откровенными текстами, но... а если вы можете проникнуть в мой экземпляр, вы можете застегнуть и загрузить весь мой веб-сервер. До тех пор, пока пользователь IAM не будет повторно использоваться для чего-либо еще и будет регулярно вращаться, представляется разумным способом решить проблему. Я что-то пропустил? Как я могу безопасно загружать частный ресурс S3 с помощью cloudinit?
Ответы
Ответ 1
Недавно Amazon анонсировала новую функцию, в которой вы можете дать "роли IAM" в своих экземплярах EC2. Это позволяет довольно просто разрешить определенным экземплярам иметь разрешение на чтение определенных ресурсов S3.
Здесь их сообщение в блоге, объявляющее о новой функции:
http://aws.typepad.com/aws/2012/06/iam-roles-for-ec2-instances-simplified-secure-access-to-aws-service-apis-from-ec2.html
Здесь раздел в документации EC2:
http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/UsingIAM.html#UsingIAMrolesWithAmazonEC2Instances
Здесь раздел в документации IAM:
http://docs.amazonwebservices.com/IAM/latest/UserGuide/WorkingWithRoles.html
Роли IAM делают учетные данные доступными для экземпляра через HTTP, поэтому любые пользователи или процессы, запущенные в экземпляре, могут видеть их.
Ответ 2
Чтобы немного обновить ответы на этот вопрос:
Наряду с ролями IAM новый клиент командной строки AWS делает выборку этих активов тривиальной. Он автоматически выведет учетные данные AWS, предоставленные через IAM из среды, и обработает обновление этих учетных данных.
Здесь пример получения одного актива из безопасного ведра S3 в пользовательских данных script:
# Install the AWS command-line tools
pip install awscli
# Fetch the asset
aws s3 cp --region us-east-1 s3://my-private-bucket/a-folder/an-asset.zip /some/destination
Просто. Вы также можете скопировать содержимое всего каталога с S3 и загрузить его и т.д. Подробнее см. справочный материал.
Ответ 3
У экземпляра с ролью IAM есть временные учетные данные безопасности, которые автоматически поворачиваются. Они доступны через http в http://169.254.169.254/latest/meta-data/iam/security-credentials/RoleName
, где RoleName - это то, что вы назвали своей ролью. Поэтому их легко получить из вашего экземпляра, но они истекают регулярно.
Использование их немного жестко. CloudFormation не может использовать временные учетные данные напрямую. Amazon Linux AMI имеет установленный Python boto, и теперь он достаточно умен, чтобы автоматически находить и использовать эти учетные данные для вас. Здесь один лайнер вы можете поместить в script для извлечения файла из ведра S3 b, ключевого k в локальный файл f:
python -c "import boto;boto.connect_s3().get_bucket('b').get_key('k').get_contents_to_filename('f')"
boto находит и использует временные учетные данные для вас, что делает его очень простым в использовании.
Ответ 4
Чтобы безопасно загрузить частный актив S3 на новый экземпляр EC2, вы должны использовать IAM Roles для EC2, чтобы предоставить необходимое разрешение S3 для ваш экземпляр EC2, затем вызовите aws s3 cp
в вашем экземпляре UserData cloudinit script для загрузки актива.
Чтобы настроить роль IAM для EC2 из шаблона CloudFormation, используйте ресурс AWS::IAM::InstanceProfile
, ссылаясь на AWS::IAM::Role
с AssumeRolePolicyDocument
делегированием доступа к ec2.amazonaws.com
с политикой, разработанной для предоставлять наименьшие привилегии (в этом случае разрешено 's3:GetObject'
только для загрузки конкретного объекта S3).
Вот полный примерный шаблон, который загружает ресурс S3 на новый экземпляр EC2 с использованием cloudinit, возвращая его содержимое как Stack Output:
![Launch Stack]()
Description: (securely) download a private S3 asset onto a new EC2 instance with cloudinit
Parameters:
S3Bucket:
Description: S3 bucket name
Type: String
S3Key:
Description: S3 object key
Type: String
Mappings:
# amzn-ami-hvm-2016.09.1.20161221-x86_64-gp2
RegionMap:
us-east-1:
"64": "ami-9be6f38c"
Resources:
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: {Service: [ ec2.amazonaws.com ]}
Action: ["sts:AssumeRole"]
Path: /
Policies:
- PolicyName: EC2Policy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: ['s3:GetObject']
Resource: !Sub 'arn:aws:s3:::${S3Bucket}/${S3Key}'
RootInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles: [ !Ref EC2Role ]
WebServer:
Type: AWS::EC2::Instance
Properties:
ImageId: !FindInMap [ RegionMap, !Ref "AWS::Region", 64 ]
InstanceType: m3.medium
IamInstanceProfile: !Ref RootInstanceProfile
UserData:
"Fn::Base64":
!Sub |
#!/bin/bash
DATA=$(aws s3 cp s3://${S3Bucket}/${S3Key} -)
/opt/aws/bin/cfn-signal \
-e $? \
-d "$DATA" \
'${Handle}'
Handle:
Type: AWS::CloudFormation::WaitConditionHandle
Wait:
Type: AWS::CloudFormation::WaitCondition
Properties:
Handle: !Ref Handle
Timeout: 300
Outputs:
Result:
Value: !GetAtt Wait.Data