Przejdź do treści

Jak stworzyć politykę oraz rolę IAM w terraform – 3 sposoby | 2022

3 ways to create AWS iam role in terraform 2022

Dzisiaj przedstawię w tutorialu 3 sposoby, na stworzenie w chmurze AWS polityki i roli IAM za pomocą Terraform. W przewodniku znajdziesz też prosty sposób, w jaki możesz połączyć wybraną politykę z Rolą IAM. Zakładam, że znasz już trochę terraforma i chmurę AWS dlatego nie będę zajmował się wyjaśnianiem podstawowych pojęć. Jeśli chcesz dowiedzieć się więcej na temat polityce i roli IAM, to możesz zajrzeć do artykułu Jak automatycznie kopiować dane z AWS S3 – Lambda events (lepczynski.it).

Sposób 1 – aws_iam_policy_document

Pierwszy sposób to stworzenie w Terraform dodatkowego elementu data aws_iam_policy_document. Ten sposób implementacji chyba spotykałem najczęściej w starszych wersjach TF. Poniżej opiszę, z czego składa się pełny plik umożliwiający stworzenie poilityki, roli i połączenie tych dwóch zasobów. Ja często grupuję różnego rodzaju zasoby w pliki, żeby łatwiej było mi je znaleźć w projekcie. W tym przykładzie przedstawiam zawartość pliku iam.tf.

data aws_iam_policy_document

W tym sposobie tworzę element data aws_iam_policy_document i w nim określam, jak ma wyglądać polityka IAM. Jest to kluczowy element i warto poświęcić mu więcej czasu. Zalecam zawsze przyznawanie tylko minimalnych, potrzebnych uprawnień. Niestety przez to rola staje się mniej uniwersalna, ale jest to cena, którą moim zdaniem warto ponieść, zwiększając dzięki temu znacząco bezpieczeństwo.

Nie mówię tu nawet o celowym działaniu, ale jeśli np. damy pełny dostęp do wszystkich S3 zamiast jednego i nasza funkcja zadziała nie tak, jak się spodziewamy, to może mieć bardzo poważne następstwa.

Dobra rada – nie rób z każdego użytkownika admina 😉

W takim dokumencie mogę zdefiniować oczywiście kilka wyrażeń. W poniższym przykładzie pozwalam na:

  • GetObject i DeleteObject w określonym folderze źródłowego S3 Bucket,
  • ListBucket źródłowego S3 i zawartości jego jednego folderu,
  • PutObjects tylko w jednym folderze docelowego S3

resource aws_iam_policy

Następnie tworzę politykę aws_iam_policy i dodaję do niej utworzony wcześniej aws_iam_policy_document.

resource aws_iam_role

Kolejnym krokiem jest stworzenie roli IAM aws_iam_role. Rolę można później przypisać do maszyny EC2, funkcji Lambda itp

resource aws_iam_role_policy_attachment

Ostatnim krokiem jest dodanie polityki do roli IAM aws_iam_role_policy_attachment. Gdybym chciał dodać więcej polityk IAM do jednej roli, to tworzę więcej zasobów aws_iam_role_policy_attachment. Podaję w nich tę samą nazwę roli i następną nazwę polityki, którą chcę dodać.

data "aws_iam_policy_document" "S3_automation_move_objects" {
  statement {
    sid = "allowS3"
    actions = [
      "s3:GetObject",
      "s3:DeleteObject",
    ]
    resources = [
      "arn:aws:s3:::test-ndgegy4364gdu-source-bucket/images/*"
    ]
  }

  statement {
    sid = "allowListBucket"
    actions = [
      "s3:ListBucket",
    ]
    resources = [
      "arn:aws:s3:::test-ndgegy4364gdu-source-bucket",
      "arn:aws:s3:::test-ndgegy4364gdu-source-bucket/images/*"
    ]
  }

  statement {
    sid = "putObject"
    actions = [
      "s3:PutObject",
    ]
    resources = [
      "arn:aws:s3:::test-ndgegy4364gdu-destination-bucket/images/*"
    ]
  }

}

resource "aws_iam_policy" "S3_automation_move_objects" {
  name        = "S3_automation_move_objects"
  description = "test - access to source and destination S3 bucket"
  path        = "/"

  policy = data.aws_iam_policy_document.S3_automation_move_objects.json
}

resource "aws_iam_role" "S3_automation_move_objects" {
  name        = "S3_automation_move_objects"
  description = "test - access to source and destination S3 bucket"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

resource "aws_iam_role_policy_attachment" "S3_automation_move_objects" {
  role       = aws_iam_role.S3_automation_move_objects.name
  policy_arn = aws_iam_policy.S3_automation_move_objects.arn
}

Sposób 2 – funkcja jsonencode

Tym razem, żeby stworzyć politykę IAM w Terraform, nie używam dodatkowych elementów. Uprawnienia definiuje bezpośrednio w aws_iam_policy. Używam tutaj specjalnej funkcji jsonencode. Ta funkcja mapuje wartości języka Terraform na wartości JSON. W tym przypadku także nie poszedłem na łatwiznę i zdefiniowałem kilka wyrażeń. Dzięki temu przypomina to bardziej realne rozwiązanie.

Tworzenie aws_iam_role oraz dodawanie polityki IAM do Roli IAM odbywa się w taki sam sposób jak w pierwszym sposobie, czyli za pomocą aws_iam_role_policy_attachment.

resource "aws_iam_policy" "S3_automation_move_objects" {
  name        = "S3_automation_move_objects"
  description = "test - access to source and destination S3 bucket"
  path        = "/"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
			"s3:GetObject",
			"s3:DeleteObject",
        ]
        Effect   = "Allow"
        Resource = "arn:aws:s3:::test-ndgegy4364gdu-source-bucket1/images/*"
      },
      {
        Action = [
			"s3:ListBucket",
        ]
        Effect   = "Allow"
        Resource = [
			"arn:aws:s3:::test-ndgegy4364gdu-source-bucket1",
			"arn:aws:s3:::test-ndgegy4364gdu-source-bucket1/images/*"
		]
      },
      {
        Action = [
			"s3:putObject",
        ]
        Effect   = "Allow"
        Resource = "arn:aws:s3:::test-ndgegy4364gdu-destination-bucket1/images/*"
      },
    ]
  })
}



resource "aws_iam_role" "S3_automation_move_objects" {
  name        = "S3_automation_move_objects"
  description = "test - access to source and destination S3 bucket"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

resource "aws_iam_role_policy_attachment" "S3_automation_move_objects" {
  role       = aws_iam_role.S3_automation_move_objects.name
  policy_arn = aws_iam_policy.S3_automation_move_objects.arn
}

Sposób 3 – EOF

Możesz także użyć trzeciego sposobu, który jest bardzo podobny do tego z punktu nr 2. Tutaj także nie definiuje dodatkowych elementów. Jednak zamiast użyć funkcji wklejamy zawartość pliku JSON.

Jeśli masz polityki IAM zdefiniowane w formacie JSON, to możesz zawartość takiej polityki bez żadnych zmian dodać w zasobie aws_iam_policy.

Tworzenie w Terraformie Roli IAM odbywa się w tak samo, jak w dwóch poprzednich sposobach. Tym razem także łączę politykę z rolą za pomocą aws_iam_role_policy_attachment.

resource "aws_iam_policy" "S3_automation_move_objects" {
  name        = "S3_automation_move_objects"
  description = "test - access to source and destination S3 bucket"
  path        = "/"

  policy = <<EOF
{
	"Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::test-ndgegy4364gdu-source-bucket1/images/*"
        },
        {
            "Action": [
                "s3:ListBucket"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:s3:::test-ndgegy4364gdu-source-bucket1",
                "arn:aws:s3:::test-ndgegy4364gdu-source-bucket1/images/*"
            ]
        },
        {
            "Action": [
                "s3:putObject"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::test-ndgegy4364gdu-destination-bucket1/images/*"
        }
    ],
    "Version": "2012-10-17"
}
EOF
}


resource "aws_iam_role" "S3_automation_move_objects" {
  name        = "S3_automation_move_objects"
  description = "test - access to source and destination S3 bucket"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Sid    = ""
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

resource "aws_iam_role_policy_attachment" "S3_automation_move_objects" {
  role       = aws_iam_role.S3_automation_move_objects.name
  policy_arn = aws_iam_policy.S3_automation_move_objects.arn
}

TEST

Na początku dobrze jest się uczyć Terraforma na kodzie który dziala, poprawiać go i dostosowywać do swoich potrzeb.

Żeby sprawdzić czy powyższe metody działają prawidłowo wystarczy że zamienisz nazwy bucketów S3 na takie które masz stworzone u siebie:

  • test-ndgegy4364gdu-source-bucket – mój źródłowy bucket z którego pobieram i usuwam dane
  • test-ndgegy4364gdu-destination-bucket – mój docelowy bucket do którego przenoszę dane
terraform apply 2022

Powyższy kod stworzy:

  • politykę IAM o nazwie ‘S3_automation_move_objects’,
  • Rolę IAM o nazwie ‘S3_automation_move_objects’,
  • Połączy Politykę IAM z rolą IAM

Podsumowanie

Wszystkie trzy sposoby tworzenia polityki IAM w Terraformie przetestowałem i sprawdziłem. W codziennej pracy możesz wybrać ten, który najbardziej Ci odpowiada albo ten, którego już wcześniej ktoś używał, żeby zachować spójność.

Jeśli znasz jeszcze jakiś sposób na stworzenie polityki IAM w Terraform, to możesz podzielić się nim w komentarzu.

Może w następnym terraformowym artykule połączę rolę IAM z EC2 albo funkcją Lambda, dzięki czemu będziemy mieli kompletne rozwiązanie i konkretny przykład użycia.

Więcej artykułów powiązanych z Dockerem albo Kubernetesem znajdziesz w Kubernetes i Docker – Wojciech Lepczyński – DevOps Cloud Architect (lepczynski.it)