Я пытаюсь использовать ECS для автоматизации развертывания инфраструктуры и приложений. Логика развертывания достаточно сложна и, вероятно, со временем станет более сложной, поэтому я решил использовать Node.js для управления оркестровкой. Некоторые шаги в развертывании требуют от меня выполнения другого двоичного файла в контейнере, в частности terraform
. Проблема заключается в том, что дочерний процесс, созданный Node.js, не обладает такими же разрешениями, как процесс Node.js.
Некоторые детали
- Контейнер ECS запускается компанией Fargate.
- Определение задачи имеет роль задачи, которая позволяет ему выполнять все необходимые действия, включая все операции, выполняемые terraform.
- Я протестировал, что разрешений достаточно, создав пользователя с одинаковыми разрешениями, который смог успешно выполнить развертывание локально.
- Я знаю, что разрешения предоставляются процессу Node.js, поскольку он может выполнять такие операции, как s3: GetObject, в частном контейнере, к которому ему предоставлен доступ с помощью роли задачи.
- Когда
terraform
пытается вызвать API-интерфейс AWS, выдается следующая ошибка: «NoCredentialProviders: в цепочке нет действительных провайдеров. Не рекомендуется.»
- Я попытался выполнить команду terraform, используя child_process.spawn, а также child_process.exec. Оба выдают одну и ту же ошибку.
После некоторого устранения этой проблемы я довольно уверен, что проблема связана с ролью задачи, не передаваемой дочернему процессу. Можно ли сделать эту раздачу? и если да, то как?
В случае, если это поможет, вот модифицированный скрипт terraform для иллюстрации при настройке ECS. Основное различие заключается в том, что в роли «Задача» больше разрешений, чем у того, который я использую.
resource "aws_ecs_task_definition" "deploy" {
family = "deploy-task"
container_definitions = <<EOF
[
{
"name": "deploy",
"image": "<ecr image uri>:latest",
"essential": true,
"memoryReservation": 128,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/deploy-task",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
EOF
task_role_arn = "${aws_iam_role.task.arn}"
execution_role_arn = "${aws_iam_role.execution.arn}"
network_mode = "awsvpc"
cpu = 256
memory = 512
requires_compatibilities = ["FARGATE"]
}
resource "aws_ecs_cluster" "deploy" {
name = "deploy-cluster"
}
resource "aws_iam_role" "task" {
name = "ecs-deploy-task"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Effect": "Allow"
}
]
}
EOF
}
resource "aws_iam_role_policy" "s3-policy" {
name = "s3-policy"
role = "${aws_iam_role.task.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "<private s3 bucket>/*"
}
]
}
EOF
}
resource "aws_iam_role" "execution" {
name = "ecs-deploy-execution"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Effect": "Allow"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "execution" {
role = "${aws_iam_role.execution.id}"
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}