Использование AWS Parameter Store для хранения credentials, ключей и другой sensitive данных, которые нежелательно хранить в открытом виде в репозитарии или в образе.
В ECS-кластере на основе EC2-инстанса запускаем Task CouchDB-prometheus-exporter, в котором происходит подключение к CouchDB-серверу для снятия статистики и предоставления метрик для мониторинг сервера(Prometheus)
В Task definition будем использовать переменные, значения которых будут динамически получаться из AWS Parameter Store(часть AWS Systems Manager), где они хранятся в зашифрованном виде и будут подставлены в контейнер в качестве переменных окружения с помощью утилиты aws-env
Порядок действий:
1 2 3 4 5 6 |
1.Создание пользовательского KMS-ключа для шифрования/расшифровывания данных. 2.Добавление необходимых параметров(любая sensistive информация с точки зрения безопасности — логины, пароли, url, ключи и т.д. в ввиде ключ/значение в AWS Parameter Store 3.Создание IAM Policy, которая разрешает доступ к этим ресурсам — установленным параметрам в AWS Systems Manager Parameter Store и KMS-ключу 4.Создание IAM Role, к которой прикрепить созданную на предыдущем этапе IAM Policy, для предоставления доступа ECS Task к параметрам в AWS Parameter Store 5.Создание ECS-кластера, Task definition и Service в ECS-кластере 6.Проверка корректно запущенного контейнера и наличие корректных значений переменных, полученных из AWS parameter Store,наличие статистики CouchDB |
1.Создание пользоватаельского KMS-ключа
Можно использовать дефолтный системный KMS-ключ, но я создам пользовательский ключ
1 |
Service→Key Management Service→Customer Managed Keys |
Узнаем KeyID
1 |
# aws kms list-keys |
1 2 3 4 5 6 7 8 |
{ "Keys": [ { "KeyArn": "arn:aws:kms:us-east-1:<account_id>:key/f632dc24-111111111111111", "KeyId": "f632dc24-111111111111111" } ] } |
Узнаем полную информацию о ключе с помощью идентификатора ключа
1 |
# aws kms describe-key --key-id f632dc24-111111111111111 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ "KeyMetadata": { "Origin": "AWS_KMS", "KeyId": "f632dc24-111111111111111", "Description": "Key for usage in parameter store", "KeyManager": "CUSTOMER", "Enabled": true, "KeyUsage": "ENCRYPT_DECRYPT", "KeyState": "Enabled", "CreationDate": 1549271245.161, "Arn": "arn:aws:kms:us-east-1:<account_id>:key/f632dc24-111111111111111", "AWSAccountId": "<account_id>" } } |
2.Добавление необходимых параметров в AWS Parameter Store
Добавим в Parameter Store следующие параметры с их соответствующими значениями
1 2 3 |
COUCHDB_USERNAME COUCHDB_PASSWORD COUCHDB_URL |
Предположим, что создаем параметры для окружения production и для приложения couchdb-exporter-myprojectname в регионе us-east-1 шифруя нашим KMS-ключем
1 |
# aws ssm put-parameter --region us-east-1 --name /production/couchdb-exporter-myprojectname/COUCHDB_USERNAME --type "SecureString" --key-id "f632dc24-111111111111111" --value "mycouchdbuser" |
1 |
# aws ssm put-parameter --region us-east-1 --name /production/couchdb-exporter-myprojectname/COUCHDB_PASSWORD --type "SecureString" --key-id "f632dc24-111111111111111" --value "mycouchdbpassword" |
Для создания параметра, значение которого содержит http:// необходимо использовать следующий формат:
1 |
# aws ssm put-parameter --region us-east-1 --cli-input-json '{"Type": "SecureString", "KeyId": "f632dc24-111111111111111", "Name": "/production/couchdb-exporter-myprojectname/COUCHDB_URI", "Value": "http://mycouchdbserver:5984"}' |
Просмотр всех установленных параметров в указанном регионе по пути /production/couchdb-exporter-myprojectname
1 |
# aws ssm get-parameters-by-path --region us-east-1 --with-decryption --path "/production/couchdb-exporter-myprojectname" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
{ "Parameters": [ { "Name": "/production/couchdb-exporter-myprojectname/COUCHDB_PASSWORD", "LastModifiedDate": 1549275449.847, "Value": "mycouchdbpassword", "Version": 2, "Type": "SecureString", "ARN": "arn:aws:ssm:us-east-1:<account_id>:parameter/production/couchdb-exporter-myprojectname/COUCHDB_PASSWORD" }, { "Name": "/production/couchdb-exporter-myprojectname/COUCHDB_URI", "LastModifiedDate": 1549275158.752, "Value": "http://mycouchdbserver:5984", "Version": 1, "Type": "SecureString", "ARN": "arn:aws:ssm:us-east-1:<account_id>:parameter/production/couchdb-exporter-myprojectname/COUCHDB_URI" }, { "Name": "/production/couchdb-exporter-myprojectname/COUCHDB_USERNAME", "LastModifiedDate": 1549274931.622, "Value": "mycouchdbuser", "Version": 1, "Type": "SecureString", "ARN": "arn:aws:ssm:us-east-1:<account_id>:parameter/production/couchdb-exporter-myprojectname/COUCHDB_USERNAME" } ] } |
Если у пользователя нет прав для создания необходимых параметров, то при попытки создать такие параметры, будет выдана ошибка типа:
1 |
An error occurred (AccessDeniedException) when calling the PutParameter operation: User: arn:aws:iam::<account-id>:user/myusername is not authorized to perform: ssm:PutParameter on resource: arn:aws:ssm:eu-east-1:<account-id>:parameter/production/couchdb-exporter-myprojectname/COUCHDB_USERNAME |
Для предоставления необходимых прав необходимо создать/добавить для пользователя следующие политики
1 2 |
AmazonSSMFullAccess AWSKeyManagementServicePowerUser |
https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-paramstore-access.html
Также parameter store могут быть созданы/изменены/просмотрены и через AWS Console(UI)
1 |
AWS Systems Manager→Parameter Store |
3. Создание IAM Policy
Создание IAM Policy с именем Parameter-Store-myprojectname-prod для доступа ECS Task-ов к AWS Systems manager и KMS-ключу(который был создан в первом пункте)
1 |
IAM→Policy→Create Policy->JSON-формат |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "ssm:GetParameterHistory", "ssm:GetParameter", "ssm:GetParameters", "ssm:GetParametersByPath" ], "Resource": [ "arn:aws:ssm:us-east-1:<account_id>:parameter/production/couchdb-exporter-myprojectname*" ], "Effect": "Allow" }, { "Action": [ "kms:Decrypt" ], "Resource": [ "arn:aws:kms:us-east-1:<account_id>:key/f632dc24-111111111111111" ], "Effect": "Allow" } ] } |
1 2 |
<account_id> - идентификатор аккаунта (account ID) f632dc24-111111111111111 – идентификатор KMS-ключа |
4.Создание IAM Role
Создание IAM роли(например, с именем Parameter-Store-myprojectname-prod-role), которая будет использоваться созданным позднее Task definition
1 |
IAM→Role→Create New Role→Elastic Container Service→Elastic Container Service Task→Next Permissions→ выбираем созданную ранее политику Parameter-Store-myprojectname-prod→Next tag→Next review-> Parameter-Store-myprojectname-prod-role |
5.Создание ECS-кластера, Task definition и Service в ECS-кластере
Создание ECS-кластера с именем couchdb-exporter-myprojectname
1 |
ECS→Cluster→Create cluster→EC2 Linux+Networking->NextStep |
1 2 3 4 5 6 7 8 9 |
Cluster name->couchdb-exporter-myprojectname Provisioning Model→On-Demand Instance EC2 Instance type→t2.micro Numbers od instances->1 Key pair→mykey VPC-Create a new VPC Security group inbound rules CIDR block→0.0.0.0/0 Port range->22 |
Создание Task definition с именем couchdb-exporter, который будет использоваться в ECS Service для запуска контейнера
1 2 3 4 5 6 7 8 |
ECS→Task Definition→Create new Task Definition→EC2→Next step Task Definition Name→couchdb-exporter Requires compatibilities ->EC2 Task Role→Parameter-Store-myprojectname-prod-role(Роль, которая была создана в пункте 4) Network Mode->Bridge Task Execution role->None Task size Memory size→128 MB |
1 2 3 4 5 6 7 8 9 10 |
Add Container Container Name→couchdb-exporter Image-> kamaok/couchdb-exporter Memory Limits Hard Limit->128Mb Soft Limit→64 Mb Port mappings-> Host Port->9984 Container Port→9984 Protocol→tcp |
Все остальные параметры оставляем по умолчанию
JSON-формат такого Task-а имеет вид( вместо <account_id> подставьте свой идентификатор AWS-аккаунта
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
{ "ipcMode": null, "executionRoleArn": null, "containerDefinitions": [ { "dnsSearchDomains": null, "logConfiguration": null, "entryPoint": null, "portMappings": [ { "hostPort": 9984, "protocol": "tcp", "containerPort": 9984 } ], "command": null, "linuxParameters": null, "cpu": 0, "environment": [], "resourceRequirements": null, "ulimits": null, "dnsServers": null, "mountPoints": [], "workingDirectory": null, "secrets": null, "dockerSecurityOptions": null, "memory": 128, "memoryReservation": 64, "volumesFrom": [], "image": "kamaok/couchdb-exporter", "disableNetworking": null, "interactive": null, "healthCheck": null, "essential": true, "links": null, "hostname": null, "extraHosts": null, "pseudoTerminal": null, "user": null, "readonlyRootFilesystem": null, "dockerLabels": null, "systemControls": null, "privileged": null, "name": "couchdb-exporter" } ], "placementConstraints": [], "memory": "128", "taskRoleArn": "arn:aws:iam::<account_id>:role/Parameter-Store-myprojectname-prod-role", "compatibilities": [ "EC2" ], "taskDefinitionArn": "arn:aws:ecs:us-east-1:<account_id>:task-definition/couchdb-exporter:1", "family": "couchdb-exporter", "requiresAttributes": [ { "targetId": null, "targetType": null, "value": null, "name": "com.amazonaws.ecs.capability.task-iam-role" }, { "targetId": null, "targetType": null, "value": null, "name": "com.amazonaws.ecs.capability.docker-remote-api.1.21" } ], "pidMode": null, "requiresCompatibilities": [ "EC2" ], "networkMode": "bridge", "cpu": null, "revision": 1, "status": "ACTIVE", "volumes": [] } |
Собираем Docker образ, используемый в Task definition
На основе базового образа gesellix/couchdb-prometheus-exporter собираем свой образ,в котором обновляем кеш пакетов, устанавливаем curl, скачиваем утилиту aws-env, которая устанавливает в контейнере в качестве переменных окружения параметры из AWS parameter Store,
копируем бинарник couchdb-prometheus-exporter, а также копируем скрипт run.sh
В Entrypoint запускаем aws-env с обязательным указанием пути, по которому нужно искать параметры и именем региона,в котором эти параметры хранятся, а также запускаем скрипт run.sh
Docker-файл для сборки образа couchdb-exporter имеет вид
1 |
# cat Dockerfile |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
FROM gesellix/couchdb-prometheus-exporter AS builder LABEL builder=true FROM ubuntu USER root RUN apt-get update && apt-get install curl -y && apt-get clean && curl -L -o /bin/aws-env https://github.com/Droplr/aws-env/raw/master/bin/aws-env-linux-amd64 && chmod +x /bin/aws-env COPY --from=builder /couchdb-prometheus-exporter /bin/couchdb-prometheus-exporter COPY ./run.sh /run.sh EXPOSE 9984 ENTRYPOINT ["/bin/bash", "-c", "eval $(AWS_ENV_PATH=/production/couchdb-exporter/ AWS_REGION=us-east-1 /bin/aws-env) && /run.sh"] |
Важно обязательно передать значения переменных
AWS_ENV_PATH и AWS_REGION
https://github.com/Droplr/aws-env/
В файле run.sh выполняется непосредственный запуск бинарника couchdb-prometheus-exporter с необходимыми параметрами для подключения к CouchDB-базе данных в виде переменных, значения которых будут динамически подставятся из предоставленных утилитой aws-env переменных как переменных окружения в контейнере
Файл run.sh имеет вид
1 |
# cat run.sh |
1 2 3 |
#!/bin/sh -e /bin/couchdb-prometheus-exporter -telemetry.address=0.0.0.0:9984 -logtostderr=true -couchdb.uri=${COUCHDB_URI} -couchdb.username=${COUCHDB_USERNAME} -couchdb.password="${COUCHDB_PASSWORD}" |
Сборка образа
1 |
# docker build -t kamaok/couchdb-exporter . |
Загрузка образа на Docker-рпеозитарий
1 |
# docker login; docker push kamaok/couchdb-exporter |
Этот образ будет использоваться в ECS Task definition
Создаем Service в ECS-кластере на основе Task Definition
1 |
Task definition→выбираем наш Task(couchdb-exporter)→выбираем версию нашего Task-а(в данны момент она у нас одна и имеет номер 1)->couchdb-exporter:1->Action->Create Service |
1 2 3 4 5 6 7 8 9 10 11 12 |
Launch Type->EC2 Task definition-> Family→couchdb-exporter Revision->1 Cluster->couchdb-exporter-myprojectname Service Name→couchdb-exporter Service type->DAEMON Number of tasks->Automatic Minimum healthy percent->0 Maximum percent->100 Deployments type→Rolling update Next step-> |
1 2 3 |
Load Balance type->None Enable Service discovery integration -> Disable Next step→ |
После создания Service проверяем состояние ECS-кластера
6.Проверка корректно запущенного контейнера и наличие корректных значений переменных, полученных из AWS parameter Store
Проверем запущенный сервис на EC2-инстансе в ECS-кластере
1 |
# docker ps | grep couchdb |
1 |
82c816590961 kamaok/couchdb-exporter "/bin/bash -c 'eval …" 16 hours ago Up 16 hours 0.0.0.0:9984->9984/tcp ecs-couchdb-exporter-myprojectname-1-couchdb-exporter-ec92beaecfefb38cca01 |
Проверяе наличие корректных значений параметров COUCHDB_URI,COUCHDB_USERNAME, COUCHDB_PASSWORD внутри контейнера
1 |
root@82c816590961:/# ps ax | grep couchdb |
1 |
12 ? Sl 0:00 /bin/couchdb-prometheus-exporter -telemetry.address=0.0.0.0:9984 -logtostderr=true -couchdb.uri=http://mycouchdbserver:5984 -couchdb.username=mycouchdbuser -couchdb.password=mycouchdbpassword |
Провреяем наличие статистики на EC2-инстансе, на котором запущен Task
Источник:
https://www.whaletech.co/2017/08/01/Secure-Credentials-for-ECS-Tasks.html
https://aws.amazon.com/ru/blogs/compute/managing-secrets-for-amazon-ecs-applications-using-parameter-store-and-iam-roles-for-tasks
https://docs.aws.amazon.com/en_us/AmazonECS/latest/developerguide/task-iam-roles.html
https://github.com/Droplr/aws-env