Работа с AWS IAM и Terraform в Unix/Linux
AWS IAM (Identity and Access Management) — это веб-сервис, который дает возможность контролировать доступ к ресурсам AWS. Вы используете IAM для контроля того, кто аутентифицирован и авторизован (имеет разрешения) для использования ресурсов. Когда вы сначала создаете учетную запись AWS, вы начинаете с единого идентификатора входа, который имеет полный доступ ко всем услугам и ресурсам AWS в рамках учетной записи. Этот идентификатор называется пользователем учетной записи в AWS, и к нему можно получить доступ, выполнив вход с адресом электронной почты и паролем, который использовался для создания учетной записи.
Рекомендуется не использовать root пользователя для выполнения ваших повседневных задач, даже административных. Он служит только для создания аккаунтов в 1-й раз, а потом не используется (для наилучшей безопастности).
Установка terraform в Unix/Linux
Установка крайне примитивная и я описал как это можно сделать тут:
Установка terraform в Unix/Linux
Так же, в данной статье, я создал скрипт для автоматической установки данного ПО. Он был протестирован на CentOS 6/7, Debian 8 и на Mac OS X. Все работает должным образом!
Работа с AWS IAM и Terraform в Unix/Linux
У меня есть папка terraform, в ней у меня будут лежать провайдеры с которыми я буду работать. Т.к в этом примере я буду использовать AWS, то создам данную папку и перейду в нее. Далее, в этой папке, стоит создать:
$ mkdir examples modules
В папке examples, я буду хранить так званые «плейбуки» для разварачивания различных служб, например — zabbix-server, grafana, web-серверы и так далее. В modules директории, я буду хранить все необходимые модули.
Начнем писать модуль, но для этой задачи, я создам папку:
$ mkir modules/iam
Переходим в нее:
$ cd modules/iam
Открываем файл:
$ vim iam.tf
В данный файл, вставляем:
#--------------------------------------------------- # Instance Profile #--------------------------------------------------- resource "aws_iam_instance_profile" "profile" { name = "${var.name}-profile-${var.environment}-${var.region}" role = "${aws_iam_role.role.name}" } #---------------------------------------------------- # IAM Role #---------------------------------------------------- resource "aws_iam_role" "role" { name = "${var.name}-role-${var.environment}-${var.region}" description = "IMA ${var.name}-role-${var.environment}-${var.region} role" path = "/" assume_role_policy ="${data.aws_iam_policy_document.role-policy-document.json}" } data "aws_iam_policy_document" "role-policy-document" { "statement" { effect = "Allow" principals { identifiers = [ "${var.aws_iam_role-principals}", ] type = "Service" } actions = [ "sts:AssumeRole", ] } } #---------------------------------------------------- # IAM Policy #---------------------------------------------------- resource "aws_iam_policy" "policy" { name = "${var.name}-policy-${var.environment}-${var.region}" description = "AIM ${var.name}-policy-${var.environment}-${var.region} policy" policy = "${data.aws_iam_policy_document.policy-document.json}" } data "aws_iam_policy_document" "policy-document" { "statement" { effect = "Allow" resources = [ "${var.aws_iam_policy-resources}", ] actions = [ "${var.aws_iam_policy-actions}", ] } } #---------------------------------------------------- # IAM Policy Attachment #---------------------------------------------------- resource "aws_iam_policy_attachment" "iam_policy_attachment" { name = "${var.name}-iam_policy_attachment-${var.environment}-${var.region}" roles = ["${aws_iam_role.role.name}"] policy_arn = "${aws_iam_policy.policy.arn}" }
Что тут описано…. Я поделил данный файл на 4 части:
- Instance Profile — Прописываем пропиль инстанса.
- IAM Role — Создаем IAM роль.
- IAM Policy — Задаем полиси для созданной IAM роли.
- IAM Policy Attachment — Прикрепляем созданную роль, полиси к инстансу.
Открываем файл:
$ vim variables.tf
И прописываем:
#----------------------------------------------------------- # Global or/and default variables #----------------------------------------------------------- variable "name" { description = "Name to be used on all resources as prefix" default = "TEST-AIM" } variable "region" { description = "The region where to deploy this code (e.g. us-east-1)." default = "us-east-1" } #--------------------------------------------------------------- # Custom variables #--------------------------------------------------------------- variable "environment" { description = "environment for service" default = "PROD" } variable "aws_iam_role-principals" { type = "list" description = "List of allowed actions." } variable "aws_iam_policy-resources" { type = "list" description = "List of allowed actions." default = ["*"] } variable "aws_iam_policy-actions" { type = "list" description = "List of allowed actions." # default = ["*"] }
Собственно в этом файле храняться все переменные. Спасибо кэп!
Открываем последний файл:
$ vim outputs.tf
и в него вставить нужно следующие строки:
output "instance_profile_uid" { value = "${aws_iam_instance_profile.profile.unique_id}" } output "role_arn" { value = "${aws_iam_role.role.arn}" } output "role_name" { value = "${aws_iam_role.role.name}" } output "policy_name" { value = "${aws_iam_policy.policy.name}" } output "AWS region" { value = "${var.region}" } output "role_id" { value = "${aws_iam_role.role.id}" }
Данный файл служит для того, чтобы выводить нужные значения на экран вашего экрана.
Переходим теперь в папку aws/examples и создадим еще одну папку для проверки написанного чуда:
$ mkdir aim && cd $_
Внутри созданной папки открываем файл:
$ vim main.tf
И вставим в него следующий код:
# # MAINTAINER Vitaliy Natarov "vitaliy.natarov@yahoo.com" # terraform { required_version = "> 0.9.0" } provider "aws" { region = "us-east-1" # access_key = "${var.aws_access_key}" # secret_key = "${var.aws_secret_key}" # } module "aim" { source = "../../modules/iam" name = "TEST-AIM" region = "us-east-1" environment = "PROD" aws_iam_role-principals = [ "ec2.amazonaws.com", ] aws_iam_policy-actions = [ "cloudwatch:GetMetricStatistics", "logs:DescribeLogStreams", "logs:GetLogEvents", "elasticache:Describe*", "rds:Describe*", "rds:ListTagsForResource", "ec2:DescribeAccountAttributes", "ec2:DescribeAvailabilityZones", "ec2:DescribeSecurityGroups", "ec2:DescribeVpcs", ] }
Все уже написано и готово к использованию. Ну что, начнем тестирование. В папке с вашим плейбуком, выполняем:
$ terraform init
Этим действием я инициализирую проект. Затем, подтягиваю модуль:
$ terraform get
PS: Для обновление изменений в самом модуле, можно выполнять:
$ terraform get -update
Запускем прогон:
$ terraform plan
Вывод будет такой:
Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. data.aws_iam_policy_document.role-policy-document: Refreshing state... data.aws_iam_policy_document.policy-document: Refreshing state... ------------------------------------------------------------------------ An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: + module.aim.aws_iam_instance_profile.profile id: <computed> arn: <computed> create_date: <computed> name: "TEST-AIM-profile-PROD-us-east-1" path: "/" role: "TEST-AIM-role-PROD-us-east-1" roles.#: <computed> unique_id: <computed> + module.aim.aws_iam_policy.policy id: <computed> arn: <computed> description: "AIM TEST-AIM-policy-PROD-us-east-1 policy" name: "TEST-AIM-policy-PROD-us-east-1" path: "/" policy: "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"rds:ListTagsForResource\",\n \"rds:Describe*\",\n \"logs:GetLogEvents\",\n \"logs:DescribeLogStreams\",\n \"elasticache:Describe*\",\n \"ec2:DescribeVpcs\",\n \"ec2:DescribeSecurityGroups\",\n \"ec2:DescribeAvailabilityZones\",\n \"ec2:DescribeAccountAttributes\",\n \"cloudwatch:GetMetricStatistics\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}" + module.aim.aws_iam_policy_attachment.iam_policy_attachment id: <computed> name: "TEST-AIM-iam_policy_attachment-PROD-us-east-1" policy_arn: "${aws_iam_policy.policy.arn}" roles.#: "1" roles.2598150538: "TEST-AIM-role-PROD-us-east-1" + module.aim.aws_iam_role.role id: <computed> arn: <computed> assume_role_policy: "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"sts:AssumeRole\",\n \"Principal\": {\n \"Service\": \"ec2.amazonaws.com\"\n }\n }\n ]\n}" create_date: <computed> description: "IMA TEST-AIM-role-PROD-us-east-1 role" force_detach_policies: "false" name: "TEST-AIM-role-PROD-us-east-1" path: "/" unique_id: <computed> Plan: 4 to add, 0 to change, 0 to destroy. ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.
Мне вывело что все у меня хорошо и можно запускать деплой:
$ terraform apply
Вывод будет:
data.aws_iam_policy_document.role-policy-document: Refreshing state... data.aws_iam_policy_document.policy-document: Refreshing state... An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: + module.aim.aws_iam_instance_profile.profile id: <computed> arn: <computed> create_date: <computed> name: "TEST-AIM-profile-PROD-us-east-1" path: "/" role: "TEST-AIM-role-PROD-us-east-1" roles.#: <computed> unique_id: <computed> + module.aim.aws_iam_policy.policy id: <computed> arn: <computed> description: "AIM TEST-AIM-policy-PROD-us-east-1 policy" name: "TEST-AIM-policy-PROD-us-east-1" path: "/" policy: "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"rds:ListTagsForResource\",\n \"rds:Describe*\",\n \"logs:GetLogEvents\",\n \"logs:DescribeLogStreams\",\n \"elasticache:Describe*\",\n \"ec2:DescribeVpcs\",\n \"ec2:DescribeSecurityGroups\",\n \"ec2:DescribeAvailabilityZones\",\n \"ec2:DescribeAccountAttributes\",\n \"cloudwatch:GetMetricStatistics\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}" + module.aim.aws_iam_policy_attachment.iam_policy_attachment id: <computed> name: "TEST-AIM-iam_policy_attachment-PROD-us-east-1" policy_arn: "${aws_iam_policy.policy.arn}" roles.#: "1" roles.2598150538: "TEST-AIM-role-PROD-us-east-1" + module.aim.aws_iam_role.role id: <computed> arn: <computed> assume_role_policy: "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"sts:AssumeRole\",\n \"Principal\": {\n \"Service\": \"ec2.amazonaws.com\"\n }\n }\n ]\n}" create_date: <computed> description: "IMA TEST-AIM-role-PROD-us-east-1 role" force_detach_policies: "false" name: "TEST-AIM-role-PROD-us-east-1" path: "/" unique_id: <computed> Plan: 4 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes module.aim.aws_iam_policy.policy: Creating... arn: "" => "<computed>" description: "" => "AIM TEST-AIM-policy-PROD-us-east-1 policy" name: "" => "TEST-AIM-policy-PROD-us-east-1" path: "" => "/" policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": [\n \"rds:ListTagsForResource\",\n \"rds:Describe*\",\n \"logs:GetLogEvents\",\n \"logs:DescribeLogStreams\",\n \"elasticache:Describe*\",\n \"ec2:DescribeVpcs\",\n \"ec2:DescribeSecurityGroups\",\n \"ec2:DescribeAvailabilityZones\",\n \"ec2:DescribeAccountAttributes\",\n \"cloudwatch:GetMetricStatistics\"\n ],\n \"Resource\": \"*\"\n }\n ]\n}" module.aim.aws_iam_role.role: Creating... arn: "" => "<computed>" assume_role_policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Action\": \"sts:AssumeRole\",\n \"Principal\": {\n \"Service\": \"ec2.amazonaws.com\"\n }\n }\n ]\n}" create_date: "" => "<computed>" description: "" => "IMA TEST-AIM-role-PROD-us-east-1 role" force_detach_policies: "" => "false" name: "" => "TEST-AIM-role-PROD-us-east-1" path: "" => "/" unique_id: "" => "<computed>" module.aim.aws_iam_policy.policy: Creation complete after 1s (ID: arn:aws:iam::316963130188:policy/TEST-AIM-policy-PROD-us-east-1) module.aim.aws_iam_role.role: Creation complete after 1s (ID: TEST-AIM-role-PROD-us-east-1) module.aim.aws_iam_instance_profile.profile: Creating... arn: "" => "<computed>" create_date: "" => "<computed>" name: "" => "TEST-AIM-profile-PROD-us-east-1" path: "" => "/" role: "" => "TEST-AIM-role-PROD-us-east-1" roles.#: "" => "<computed>" unique_id: "" => "<computed>" module.aim.aws_iam_policy_attachment.iam_policy_attachment: Creating... name: "" => "TEST-AIM-iam_policy_attachment-PROD-us-east-1" policy_arn: "" => "arn:aws:iam::316963130188:policy/TEST-AIM-policy-PROD-us-east-1" roles.#: "" => "1" roles.2598150538: "" => "TEST-AIM-role-PROD-us-east-1" module.aim.aws_iam_instance_profile.profile: Creation complete after 2s (ID: TEST-AIM-profile-PROD-us-east-1) module.aim.aws_iam_policy_attachment.iam_policy_attachment: Creation complete after 3s (ID: TEST-AIM-iam_policy_attachment-PROD-us-east-1) Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Как видно с вывода, — все прошло гладко! Чтобы удалить созданное творение, можно выполнить:
$ terraform destroy
Вот и все на этом. Данная статья «Работа с AWS IAM и Terraform в Unix/Linux» завершена.