diff --git a/examples/iam/developers/.terraform.lock.hcl b/examples/iam/developers/.terraform.lock.hcl
new file mode 100644
index 0000000..c4390a6
--- /dev/null
+++ b/examples/iam/developers/.terraform.lock.hcl
@@ -0,0 +1,44 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+ version = "4.57.0"
+ constraints = ">= 4.0.0"
+ hashes = [
+ "h1:xMOeHMZM7RAO6HKP2C6XbbBjGdHogTJ3CwPRw6xFj30=",
+ "zh:07d89ad94267b7d6285fd65fbd67f8680e111abf9bbcbcac2e30154262fbbe46",
+ "zh:0eeee044e6fc285c20241d3de7f9b79450cab2df1452a9c18c0bed1090085a25",
+ "zh:306ba8ac99a0d9f9eba0386cb11459323696e69dcb28bc5e55b6fb2de28640cd",
+ "zh:40afc24b94e7cae387f22dd3045b09311a120e429aa4f06168d7498995a98f67",
+ "zh:5a2c846a2cc463841ca2353fb734ba6f9502e662196c85fd3332a4e18acec72e",
+ "zh:854fbf7d058e4e31ce4ed882e2085bd94c53be4b38b15f3b5d3d897a2c5102df",
+ "zh:89a7a5e7de6400662804d5dc43251172e3f0522853dcab304d637a7bbb266654",
+ "zh:89ef96a1b36396f555e80505f55fd29432be3dc518bd75b72a1aae29e8171b4a",
+ "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+ "zh:b28516cc8e614fad40738ec73ce70528e2a817dae3118895333c1d63f1e22a89",
+ "zh:c3f1c6a7d56b0838da2f880a74e19df65ca9006cb3ebdc34403cb9d6e4ee046d",
+ "zh:d036a7355494792e2347b92d766431ba91cb399a4bd2bb719db3025542c0e674",
+ "zh:d3299b9507085238aaf24f38faffb5d6226a31f916e47320b31d728c7062be16",
+ "zh:d9f5c04f4648d593d91be2a66c6c61f6c52512c78ac6fb3077f0911a6b95fa2f",
+ "zh:f84143ee0cff2ad0af8ad40074fb5dcd83bfb8a514c7f43ca23c7422caa42330",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+ version = "3.4.3"
+ hashes = [
+ "h1:tL3katm68lX+4lAncjQA9AXL4GR/VM+RPwqYf4D2X8Q=",
+ "zh:41c53ba47085d8261590990f8633c8906696fa0a3c4b384ff6a7ecbf84339752",
+ "zh:59d98081c4475f2ad77d881c4412c5129c56214892f490adf11c7e7a5a47de9b",
+ "zh:686ad1ee40b812b9e016317e7f34c0d63ef837e084dea4a1f578f64a6314ad53",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:84103eae7251384c0d995f5a257c72b0096605048f757b749b7b62107a5dccb3",
+ "zh:8ee974b110adb78c7cd18aae82b2729e5124d8f115d484215fd5199451053de5",
+ "zh:9dd4561e3c847e45de603f17fa0c01ae14cae8c4b7b4e6423c9ef3904b308dda",
+ "zh:bb07bb3c2c0296beba0beec629ebc6474c70732387477a65966483b5efabdbc6",
+ "zh:e891339e96c9e5a888727b45b2e1bb3fcbdfe0fd7c5b4396e4695459b38c8cb1",
+ "zh:ea4739860c24dfeaac6c100b2a2e357106a89d18751f7693f3c31ecf6a996f8d",
+ "zh:f0c76ac303fd0ab59146c39bc121c5d7d86f878e9a69294e29444d4c653786f8",
+ "zh:f143a9a5af42b38fed328a161279906759ff39ac428ebcfe55606e05e1518b93",
+ ]
+}
diff --git a/examples/iam/developers/README.md b/examples/iam/developers/README.md
new file mode 100644
index 0000000..d7e29d2
--- /dev/null
+++ b/examples/iam/developers/README.md
@@ -0,0 +1,14 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [secrets](#module\_secrets) | ../../../modules/iam/developers | n/a |
+
\ No newline at end of file
diff --git a/examples/iam/developers/main.tf b/examples/iam/developers/main.tf
new file mode 100644
index 0000000..29d6303
--- /dev/null
+++ b/examples/iam/developers/main.tf
@@ -0,0 +1,5 @@
+module "secrets" {
+ source = "../../../modules/iam/developers"
+
+ users = ["test@test.com"]
+}
\ No newline at end of file
diff --git a/examples/iam/developers/versions.tf b/examples/iam/developers/versions.tf
new file mode 100644
index 0000000..069b09d
--- /dev/null
+++ b/examples/iam/developers/versions.tf
@@ -0,0 +1,14 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+}
+
+provider "aws" {
+ region = "eu-central-1"
+}
\ No newline at end of file
diff --git a/examples/iam/ecr-pull-push/.terraform.lock.hcl b/examples/iam/ecr-pull-push/.terraform.lock.hcl
new file mode 100644
index 0000000..62397a5
--- /dev/null
+++ b/examples/iam/ecr-pull-push/.terraform.lock.hcl
@@ -0,0 +1,21 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+ version = "3.70.0"
+ constraints = "~> 3.0"
+ hashes = [
+ "h1:jn4ImGMZJ9rQdaVSbcCBqUqnhRSpyaM1DivqaNuP+eg=",
+ "zh:0af710e528e21b930899f0ac295b0ceef8ad7b623dd8f38e92c8ec4bc7af0321",
+ "zh:4cabcd4519c0aae474d91ae67a8e3a4a8c39c3945c289a9cf7c1409f64409abe",
+ "zh:58da1a436facb4e4f95cd2870d211ed7bcb8cf721a4a61970aa8da191665f2aa",
+ "zh:6465339475c1cd3c16a5c8fee61304dcad2c4a27740687d29c6cdc90d2e6423d",
+ "zh:7a821ed053c355d70ebe33185590953fa5c364c1f3d66fe3f9b4aba3961646b1",
+ "zh:7c3656cc9cc1739dcb298e7930c9a76ccfce738d2070841d7e6c62fbdae74eef",
+ "zh:9d9da9e3c60a0c977e156da8590f36a219ae91994bb3df5a1208de2ab3ceeba7",
+ "zh:a3138817c86bf3e4dca7fd3a92e099cd1bf1d45ee7c7cc9e9773ba04fc3b315a",
+ "zh:a8603044e935dfb3cb9319a46d26276162c6aea75e02c4827232f9c6029a3182",
+ "zh:aef9482332bf43d0b73317f5909dec9e95b983c67b10d72e75eacc7c4f37d084",
+ "zh:fc3f3cad84f2eebe566dd0b65904c934093007323b9b85e73d9dd4535ceeb29d",
+ ]
+}
diff --git a/examples/iam/ecr-pull-push/README.md b/examples/iam/ecr-pull-push/README.md
new file mode 100644
index 0000000..3fdba46
--- /dev/null
+++ b/examples/iam/ecr-pull-push/README.md
@@ -0,0 +1,41 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 3.70.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [aws\_iam\_ecr\_policy](#module\_aws\_iam\_ecr\_policy) | ../../../modules/iam/ecr-pull-push | n/a |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_ecr_repository.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |
+| [aws_iam_access_key.pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
+| [aws_iam_access_key.push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
+| [aws_iam_user.pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
+| [aws_iam_user.push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [ecr\_registry\_id](#output\_ecr\_registry\_id) | n/a |
+| [ecr\_repository\_url](#output\_ecr\_repository\_url) | n/a |
+| [iam\_pull\_user\_id](#output\_iam\_pull\_user\_id) | n/a |
+| [iam\_pull\_user\_secret](#output\_iam\_pull\_user\_secret) | n/a |
+| [iam\_push\_user\_id](#output\_iam\_push\_user\_id) | n/a |
+| [iam\_push\_user\_secret](#output\_iam\_push\_user\_secret) | n/a |
+
\ No newline at end of file
diff --git a/examples/iam/ecr-pull-push/main.tf b/examples/iam/ecr-pull-push/main.tf
new file mode 100644
index 0000000..903ae06
--- /dev/null
+++ b/examples/iam/ecr-pull-push/main.tf
@@ -0,0 +1,57 @@
+resource "aws_ecr_repository" "this" {
+ name = "aws-iam-ecr"
+
+ image_scanning_configuration {
+ scan_on_push = true
+ }
+}
+
+output "ecr_registry_id" {
+ value = aws_ecr_repository.this.registry_id
+}
+
+output "ecr_repository_url" {
+ value = aws_ecr_repository.this.repository_url
+}
+
+resource "aws_iam_user" "pull" {
+ name = "ecr-pull"
+}
+
+resource "aws_iam_access_key" "pull" {
+ user = aws_iam_user.pull.name
+}
+
+output "iam_pull_user_id" {
+ value = aws_iam_access_key.pull.id
+}
+
+output "iam_pull_user_secret" {
+ value = aws_iam_access_key.pull.secret
+ sensitive = true
+}
+
+resource "aws_iam_user" "push" {
+ name = "ecr-push"
+}
+
+resource "aws_iam_access_key" "push" {
+ user = aws_iam_user.push.name
+}
+
+output "iam_push_user_id" {
+ value = aws_iam_access_key.push.id
+}
+
+output "iam_push_user_secret" {
+ value = aws_iam_access_key.push.secret
+ sensitive = true
+}
+
+module "aws_iam_ecr_policy" {
+ source = "../../../modules/iam/ecr-pull-push"
+ name_prefix = "aws-iam"
+ ecr_arn = aws_ecr_repository.this.arn
+ pull_users = [aws_iam_user.pull.name]
+ push_users = [aws_iam_user.push.name]
+}
diff --git a/examples/iam/ecr-pull-push/versions.tf b/examples/iam/ecr-pull-push/versions.tf
new file mode 100644
index 0000000..ca530cc
--- /dev/null
+++ b/examples/iam/ecr-pull-push/versions.tf
@@ -0,0 +1,13 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+ required_version = "~> 1.0"
+}
+
+provider "aws" {
+ region = "eu-central-1"
+}
diff --git a/examples/iam/ecs-deploy/.terraform.lock.hcl b/examples/iam/ecs-deploy/.terraform.lock.hcl
new file mode 100644
index 0000000..40270eb
--- /dev/null
+++ b/examples/iam/ecs-deploy/.terraform.lock.hcl
@@ -0,0 +1,57 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+ version = "3.70.0"
+ constraints = "~> 3.0, >= 3.63.0"
+ hashes = [
+ "h1:jn4ImGMZJ9rQdaVSbcCBqUqnhRSpyaM1DivqaNuP+eg=",
+ "zh:0af710e528e21b930899f0ac295b0ceef8ad7b623dd8f38e92c8ec4bc7af0321",
+ "zh:4cabcd4519c0aae474d91ae67a8e3a4a8c39c3945c289a9cf7c1409f64409abe",
+ "zh:58da1a436facb4e4f95cd2870d211ed7bcb8cf721a4a61970aa8da191665f2aa",
+ "zh:6465339475c1cd3c16a5c8fee61304dcad2c4a27740687d29c6cdc90d2e6423d",
+ "zh:7a821ed053c355d70ebe33185590953fa5c364c1f3d66fe3f9b4aba3961646b1",
+ "zh:7c3656cc9cc1739dcb298e7930c9a76ccfce738d2070841d7e6c62fbdae74eef",
+ "zh:9d9da9e3c60a0c977e156da8590f36a219ae91994bb3df5a1208de2ab3ceeba7",
+ "zh:a3138817c86bf3e4dca7fd3a92e099cd1bf1d45ee7c7cc9e9773ba04fc3b315a",
+ "zh:a8603044e935dfb3cb9319a46d26276162c6aea75e02c4827232f9c6029a3182",
+ "zh:aef9482332bf43d0b73317f5909dec9e95b983c67b10d72e75eacc7c4f37d084",
+ "zh:fc3f3cad84f2eebe566dd0b65904c934093007323b9b85e73d9dd4535ceeb29d",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/cloudinit" {
+ version = "2.2.0"
+ hashes = [
+ "h1:siiI0wK6/jUDdA5P8ifTO0yc9YmXHml4hz5K9I9N+MA=",
+ "zh:76825122171f9ea2287fd27e23e80a7eb482f6491a4f41a096d77b666896ee96",
+ "zh:795a36dee548e30ca9c9d474af9ad6d29290e0a9816154ad38d55381cd0ab12d",
+ "zh:9200f02cb917fb99e44b40a68936fd60d338e4d30a718b7e2e48024a795a61b9",
+ "zh:a33cf255dc670c20678063aa84218e2c1b7a67d557f480d8ec0f68bc428ed472",
+ "zh:ba3c1b2cd0879286c1f531862c027ec04783ece81de67c9a3b97076f1ce7f58f",
+ "zh:bd575456394428a1a02191d2e46af0c00e41fd4f28cfe117d57b6aeb5154a0fb",
+ "zh:c68dd1db83d8437c36c92dc3fc11d71ced9def3483dd28c45f8640cfcd59de9a",
+ "zh:cbfe34a90852ed03cc074601527bb580a648127255c08589bc3ef4bf4f2e7e0c",
+ "zh:d6ffd7398c6d1f359b96f5b757e77b99b339fbb91df1b96ac974fe71bc87695c",
+ "zh:d9c15285f847d7a52df59e044184fb3ba1b7679fd0386291ed183782683d9517",
+ "zh:f7dd02f6d36844da23c9a27bb084503812c29c1aec4aba97237fec16860fdc8c",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/random" {
+ version = "3.1.0"
+ hashes = [
+ "h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=",
+ "zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc",
+ "zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626",
+ "zh:4f251b0eda5bb5e3dc26ea4400dba200018213654b69b4a5f96abee815b4f5ff",
+ "zh:7011332745ea061e517fe1319bd6c75054a314155cb2c1199a5b01fe1889a7e2",
+ "zh:738ed82858317ccc246691c8b85995bc125ac3b4143043219bd0437adc56c992",
+ "zh:7dbe52fac7bb21227acd7529b487511c91f4107db9cc4414f50d04ffc3cab427",
+ "zh:a3a9251fb15f93e4cfc1789800fc2d7414bbc18944ad4c5c98f466e6477c42bc",
+ "zh:a543ec1a3a8c20635cf374110bd2f87c07374cf2c50617eee2c669b3ceeeaa9f",
+ "zh:d9ab41d556a48bd7059f0810cf020500635bfc696c9fc3adab5ea8915c1d886b",
+ "zh:d9e13427a7d011dbd654e591b0337e6074eef8c3b9bb11b2e39eaaf257044fd7",
+ "zh:f7605bd1437752114baf601bdf6931debe6dc6bfe3006eb7e9bb9080931dca8a",
+ ]
+}
diff --git a/examples/iam/ecs-deploy/README.md b/examples/iam/ecs-deploy/README.md
new file mode 100644
index 0000000..78d8ea2
--- /dev/null
+++ b/examples/iam/ecs-deploy/README.md
@@ -0,0 +1,40 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 3.70.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [aws\_iam\_ecs\_policy](#module\_aws\_iam\_ecs\_policy) | ../../../modules/iam/ecs-deploy | n/a |
+| [ecs\_cluster](#module\_ecs\_cluster) | Selleo/backend/aws//modules/ecs-cluster | n/a |
+| [ecs\_service](#module\_ecs\_service) | Selleo/backend/aws//modules/ecs-service | n/a |
+| [lb](#module\_lb) | Selleo/backend/aws//modules/load-balancer | n/a |
+| [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | n/a |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_alb_listener.http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener) | resource |
+| [aws_iam_access_key.ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
+| [aws_iam_user.ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [ecs\_cluster\_id](#output\_ecs\_cluster\_id) | n/a |
+| [iam\_user\_id](#output\_iam\_user\_id) | n/a |
+| [iam\_user\_secret](#output\_iam\_user\_secret) | n/a |
+
\ No newline at end of file
diff --git a/examples/iam/ecs-deploy/main.tf b/examples/iam/ecs-deploy/main.tf
new file mode 100644
index 0000000..9c2f029
--- /dev/null
+++ b/examples/iam/ecs-deploy/main.tf
@@ -0,0 +1,109 @@
+# ECS setup is taken from: https://github.com/Selleo/terraform-aws-backend/blob/main/examples/basic-ecs-setup/main.tf
+
+module "vpc" {
+ source = "terraform-aws-modules/vpc/aws"
+
+ name = "test"
+ cidr = "10.0.0.0/16"
+
+ azs = ["eu-central-1a", "eu-central-1b"]
+ private_subnets = ["10.0.1.0/24"]
+ public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
+
+ enable_nat_gateway = false
+ enable_vpn_gateway = false
+
+ tags = {
+ Terraform = "true"
+ Environment = "test"
+ }
+}
+
+module "lb" {
+ source = "Selleo/backend/aws//modules/load-balancer"
+
+ name = "ecs-lb"
+ vpc_id = module.vpc.vpc_id
+ subnet_ids = module.vpc.public_subnets
+
+ tags = {
+ Terraform = "true"
+ Environment = "test"
+ }
+}
+
+module "ecs_cluster" {
+ source = "Selleo/backend/aws//modules/ecs-cluster"
+
+ name_prefix = "test"
+ region = "eu-central-1"
+ vpc_id = module.vpc.vpc_id
+ subnet_ids = module.vpc.public_subnets
+ instance_type = "t3.micro"
+ security_groups = []
+ loadbalancer_sg_id = module.lb.loadbalancer_sg_id
+ autoscaling_group = {
+ min_size = 1
+ max_size = 1
+ desired_capacity = 1
+ }
+}
+
+module "ecs_service" {
+ source = "Selleo/backend/aws//modules/ecs-service"
+
+ name = "test"
+ vpc_id = module.vpc.vpc_id
+ ecs_cluster_id = module.ecs_cluster.ecs_cluster_id
+ desired_count = 1
+ instance_role = module.ecs_cluster.instance_role
+ container_definition = {
+ cpu_units = 256
+ mem_units = 256
+ command = ["bundle", "exec", "ruby", "main.rb"],
+ image = "qbart/hello-ruby-sinatra:latest",
+ container_port = 4567
+ envs = {
+ "APP_ENV" = "production"
+ }
+ }
+}
+
+resource "aws_alb_listener" "http" {
+ load_balancer_arn = module.lb.loadbalancer_id
+ port = 80
+ protocol = "HTTP"
+
+ default_action {
+ target_group_arn = module.ecs_service.lb_target_group_id
+ type = "forward"
+ }
+}
+
+output "ecs_cluster_id" {
+ value = module.ecs_cluster.ecs_cluster_id
+}
+
+resource "aws_iam_user" "ecs" {
+ name = "ecs"
+}
+
+resource "aws_iam_access_key" "ecs" {
+ user = aws_iam_user.ecs.name
+}
+
+output "iam_user_id" {
+ value = aws_iam_access_key.ecs.id
+}
+
+output "iam_user_secret" {
+ value = aws_iam_access_key.ecs.secret
+ sensitive = true
+}
+
+module "aws_iam_ecs_policy" {
+ source = "../../../modules/iam/ecs-deploy"
+ name_prefix = "aws-iam"
+ service_arn = module.ecs_service.service_id
+ users = [aws_iam_user.ecs.name]
+}
diff --git a/examples/iam/ecs-deploy/versions.tf b/examples/iam/ecs-deploy/versions.tf
new file mode 100644
index 0000000..ca530cc
--- /dev/null
+++ b/examples/iam/ecs-deploy/versions.tf
@@ -0,0 +1,13 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+ required_version = "~> 1.0"
+}
+
+provider "aws" {
+ region = "eu-central-1"
+}
diff --git a/examples/iam/s3-read-write/.terraform.lock.hcl b/examples/iam/s3-read-write/.terraform.lock.hcl
new file mode 100644
index 0000000..2395ead
--- /dev/null
+++ b/examples/iam/s3-read-write/.terraform.lock.hcl
@@ -0,0 +1,22 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+ version = "4.38.0"
+ constraints = "~> 4.0"
+ hashes = [
+ "h1:LympybKZJE3L0H12nMmDnFH1iexD9S2GqZbDMo4fuPI=",
+ "zh:0ae61458acf7acecf47f7a02e08da1f7adeee9532e053c0d80432f16197e4799",
+ "zh:1ece9bcef41ffc75e0955419d7f8b1708ab7ffe4518bc9a2afe3bc5c79a9e79b",
+ "zh:302065a7c3ae798345b92a465b650b025d9c4e9abc3e78421ecc69a17b8c3d6a",
+ "zh:52d61f6a3ed6726b821a78f1fb78df818cf24a4d2378cc16afded297b37d4b7b",
+ "zh:6c365ed0cae031acdbcca04560997589a94629269cb456d468cbe51a3a020386",
+ "zh:70987a51d782f3458f124efea320157a48453864c420421051c56d41e463a948",
+ "zh:8b5a5f30240c67e596a89ccd76aa81133e6ae253c8a06a932b8901ef2b4a7486",
+ "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+ "zh:d672167515ece7c2db4663faf180dfb6cfc6dbf5e149f868d05c39bb54b9ca03",
+ "zh:df1bc9926674b2e1246c9ebffd8bf8c4e380f50910a7f0b3ded957e8768ae27a",
+ "zh:e304b6e2bd66e7992326aa0446152547eb97e8f77d00bc1a9096022ac37e5d71",
+ "zh:f033690f11446af1383ad74149f429fae19e2784af5e151a22f46965dff21b29",
+ ]
+}
diff --git a/examples/iam/s3-read-write/README.md b/examples/iam/s3-read-write/README.md
new file mode 100644
index 0000000..6e7d1e1
--- /dev/null
+++ b/examples/iam/s3-read-write/README.md
@@ -0,0 +1,35 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 4.38.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [s3\_full\_access\_policy](#module\_s3\_full\_access\_policy) | ../../../modules/iam/s3-read-write | n/a |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_access_key.s3_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
+| [aws_iam_user.s3_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
+| [aws_s3_bucket.example_s3_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [iam\_user\_id](#output\_iam\_user\_id) | n/a |
+| [iam\_user\_secret](#output\_iam\_user\_secret) | n/a |
+
\ No newline at end of file
diff --git a/examples/iam/s3-read-write/main.tf b/examples/iam/s3-read-write/main.tf
new file mode 100644
index 0000000..156f203
--- /dev/null
+++ b/examples/iam/s3-read-write/main.tf
@@ -0,0 +1,28 @@
+resource "aws_s3_bucket" "example_s3_bucket" {
+ bucket = "tf-iam-example-s3-bucket"
+ acl = "private"
+}
+
+resource "aws_iam_user" "s3_user" {
+ name = "s3_user"
+}
+
+resource "aws_iam_access_key" "s3_user" {
+ user = aws_iam_user.s3_user.name
+}
+
+output "iam_user_id" {
+ value = aws_iam_access_key.s3_user.id
+}
+
+output "iam_user_secret" {
+ value = aws_iam_access_key.s3_user.secret
+ sensitive = true
+}
+
+module "s3_full_access_policy" {
+ source = "../../../modules/iam/s3-read-write"
+ name_prefix = "aws-iam"
+ bucket_arn = aws_s3_bucket.example_s3_bucket.arn
+ users = [aws_iam_user.s3_user.name]
+}
diff --git a/examples/iam/s3-read-write/versions.tf b/examples/iam/s3-read-write/versions.tf
new file mode 100644
index 0000000..ca530cc
--- /dev/null
+++ b/examples/iam/s3-read-write/versions.tf
@@ -0,0 +1,13 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+ required_version = "~> 1.0"
+}
+
+provider "aws" {
+ region = "eu-central-1"
+}
diff --git a/examples/iam/secret-manager/.terraform.lock.hcl b/examples/iam/secret-manager/.terraform.lock.hcl
new file mode 100644
index 0000000..a7e36bf
--- /dev/null
+++ b/examples/iam/secret-manager/.terraform.lock.hcl
@@ -0,0 +1,40 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+ version = "3.69.0"
+ constraints = "~> 3.0"
+ hashes = [
+ "h1:DFUb87/IK9l6anGAagwkDZ3x62p18JCljU8he5SfLrM=",
+ "h1:PBvQ5w86YSJqL5x7lAwKYxdd7NRyNCTlXz3S61VQWZk=",
+ "zh:0cedd84ba908ba7190052b16cd7f70c41b0e2c2e914e54eecf2e3dae193f47fa",
+ "zh:14b89bac6412e20d415fe67d5f2eaa1414d9bbf75a5bd8fc963f6ab8e3b8b1a0",
+ "zh:159131129edab7ea118dee7d6daf1bfe4615f200a2d5120deb8369cbd2c4b598",
+ "zh:32a3a35964c9becb167180df905f34eb0cae7c30e00452527a0e600ee95c033f",
+ "zh:5330374066ca27d9a00ca667c81183c1dbfa0fcfdd5c1797a6185b76bc7c13bc",
+ "zh:78b75c45b7c660efaf89428ca988a77a4f55eba359f95ed7a54efe87fad1ab8b",
+ "zh:81f723c3f33dc0761ed12b025c1f411fe22f2c6a97e22f4adeb10f7668a5df8f",
+ "zh:98053adb091233fea8c1a82768dfce994e8407e2cb948d28ff88865d2d9a4dcd",
+ "zh:a52866826b51c0b4cb6b970cb3328542846e108c8f4d24c090d7ca0ffa341e44",
+ "zh:a9923cbdf30e9b66f889fef22e1f4b657d9ac1a48812f476ef841405a3c11525",
+ "zh:c079f98be9b8456e6eae6c07c5dcb84ecbcbb70b2f361f1c6f9c3ba90366d905",
+ ]
+}
+
+provider "registry.terraform.io/hashicorp/tls" {
+ version = "3.1.0"
+ hashes = [
+ "h1:U+kgPLboCrcs4eZV87esP7iydF8mjMyHKE/mDsrwfkQ=",
+ "zh:3d46616b41fea215566f4a957b6d3a1aa43f1f75c26776d72a98bdba79439db6",
+ "zh:623a203817a6dafa86f1b4141b645159e07ec418c82fe40acd4d2a27543cbaa2",
+ "zh:668217e78b210a6572e7b0ecb4134a6781cc4d738f4f5d09eb756085b082592e",
+ "zh:95354df03710691773c8f50a32e31fca25f124b7f3d6078265fdf3c4e1384dca",
+ "zh:9f97ab190380430d57392303e3f36f4f7835c74ea83276baa98d6b9a997c3698",
+ "zh:a16f0bab665f8d933e95ca055b9c8d5707f1a0dd8c8ecca6c13091f40dc1e99d",
+ "zh:be274d5008c24dc0d6540c19e22dbb31ee6bfdd0b2cddd4d97f3cd8a8d657841",
+ "zh:d5faa9dce0a5fc9d26b2463cea5be35f8586ab75030e7fa4d4920cd73ee26989",
+ "zh:e9b672210b7fb410780e7b429975adcc76dd557738ecc7c890ea18942eb321a5",
+ "zh:eb1f8368573d2370605d6dbf60f9aaa5b64e55741d96b5fb026dbfe91de67c0d",
+ "zh:fc1e12b713837b85daf6c3bb703d7795eaf1c5177aebae1afcf811dd7009f4b0",
+ ]
+}
diff --git a/examples/iam/secret-manager/README.md b/examples/iam/secret-manager/README.md
new file mode 100644
index 0000000..943aa4c
--- /dev/null
+++ b/examples/iam/secret-manager/README.md
@@ -0,0 +1,44 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0.5 |
+| [aws](#requirement\_aws) | ~> 3.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 3.69.0 |
+| [tls](#provider\_tls) | 3.1.0 |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [aws\_iam\_secret\_manager\_policy](#module\_aws\_iam\_secret\_manager\_policy) | ../../../modules/iam/secrets-manager | n/a |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_access_key.full_access_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
+| [aws_iam_access_key.read_only_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
+| [aws_iam_user.full_access_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
+| [aws_iam_user.read_only_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
+| [aws_secretsmanager_secret.secret_no_1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
+| [aws_secretsmanager_secret.secret_no_2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
+| [aws_secretsmanager_secret_version.bin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource |
+| [aws_secretsmanager_secret_version.kv](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource |
+| [tls_private_key.app](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [iam\_user1\_id](#output\_iam\_user1\_id) | n/a |
+| [iam\_user1\_secret](#output\_iam\_user1\_secret) | n/a |
+| [iam\_user2\_id](#output\_iam\_user2\_id) | n/a |
+| [iam\_user2\_secret](#output\_iam\_user2\_secret) | n/a |
+
\ No newline at end of file
diff --git a/examples/iam/secret-manager/main.tf b/examples/iam/secret-manager/main.tf
new file mode 100644
index 0000000..a597f3f
--- /dev/null
+++ b/examples/iam/secret-manager/main.tf
@@ -0,0 +1,71 @@
+resource "aws_secretsmanager_secret" "secret_no_1" {
+ name = "secret_no_1"
+}
+
+resource "aws_secretsmanager_secret_version" "kv" {
+ secret_id = aws_secretsmanager_secret.secret_no_1.id
+ secret_string = jsonencode({
+ key1 = "value1"
+ key2 = "value2"
+ }
+ )
+}
+
+resource "aws_secretsmanager_secret" "secret_no_2" {
+ name = "secret_no_2"
+}
+
+resource "tls_private_key" "app" {
+ algorithm = "RSA"
+}
+
+resource "aws_secretsmanager_secret_version" "bin" {
+ secret_id = aws_secretsmanager_secret.secret_no_2.id
+ secret_binary = base64encode(tls_private_key.app.private_key_pem)
+}
+
+resource "aws_iam_user" "read_only_user" {
+ name = "read_only_user"
+}
+
+resource "aws_iam_access_key" "read_only_user" {
+ user = aws_iam_user.read_only_user.name
+}
+
+output "iam_user1_id" {
+ value = aws_iam_access_key.read_only_user.id
+}
+
+output "iam_user1_secret" {
+ value = aws_iam_access_key.read_only_user.secret
+ sensitive = true
+}
+
+resource "aws_iam_user" "full_access_user" {
+ name = "full_access_user"
+}
+
+resource "aws_iam_access_key" "full_access_user" {
+ user = aws_iam_user.full_access_user.name
+}
+
+output "iam_user2_id" {
+ value = aws_iam_access_key.full_access_user.id
+}
+
+output "iam_user2_secret" {
+ value = aws_iam_access_key.full_access_user.secret
+ sensitive = true
+}
+
+module "aws_iam_secret_manager_policy" {
+ source = "../../../modules/iam/secrets-manager"
+ name_prefix = "aws-iam-secrets-manager"
+ secrets = [
+ aws_secretsmanager_secret.secret_no_1.arn,
+ aws_secretsmanager_secret.secret_no_2.arn,
+ ]
+ read_users = [aws_iam_user.read_only_user.name]
+ write_users = [aws_iam_user.full_access_user.name]
+}
+
diff --git a/examples/iam/secret-manager/versions.tf b/examples/iam/secret-manager/versions.tf
new file mode 100644
index 0000000..bc2aff7
--- /dev/null
+++ b/examples/iam/secret-manager/versions.tf
@@ -0,0 +1,13 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 3.0"
+ }
+ }
+ required_version = "~> 1.0.5"
+}
+
+provider "aws" {
+ region = "eu-central-1"
+}
diff --git a/examples/iam/user-with-access-key/README.md b/examples/iam/user-with-access-key/README.md
new file mode 100644
index 0000000..9861eef
--- /dev/null
+++ b/examples/iam/user-with-access-key/README.md
@@ -0,0 +1,29 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | >= 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | >= 4.0 |
+| [random](#provider\_random) | n/a |
+
+## Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [iam\_app\_xyz](#module\_iam\_app\_xyz) | ../../../modules/iam/user-with-access-key | n/a |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_group.app_xyz_s3_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_group) | resource |
+| [aws_iam_policy.app_xyz_read_ec2](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [random_id.id](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
+
\ No newline at end of file
diff --git a/examples/iam/user-with-access-key/main.tf b/examples/iam/user-with-access-key/main.tf
new file mode 100644
index 0000000..837b4e3
--- /dev/null
+++ b/examples/iam/user-with-access-key/main.tf
@@ -0,0 +1,36 @@
+module "iam_app_xyz" {
+ source = "../../../modules/iam/user-with-access-key"
+
+ name = "app-xyz-${random_id.id.hex}"
+
+ groups = [aws_iam_group.app_xyz_s3_access.id]
+ policies = [aws_iam_policy.app_xyz_read_ec2.id]
+}
+
+resource "random_id" "id" {
+ byte_length = 2
+}
+
+resource "aws_iam_group" "app_xyz_s3_access" {
+ name = "app-xyz-s3-access-${random_id.id.hex}"
+}
+# ☝️ actual policy is omitted for brevity
+
+resource "aws_iam_policy" "app_xyz_read_ec2" {
+ name = "app-xyz-ec2-read-${random_id.id.hex}"
+
+ policy = jsonencode({
+ Version = "2012-10-17"
+ Statement = [
+ {
+ Action = [
+ "ec2:Describe*",
+ ]
+ Effect = "Allow"
+ Resource = "*"
+ },
+ ]
+ })
+}
+
+# ☝️ actual policy is omitted for brevity
diff --git a/examples/iam/user-with-access-key/versions.tf b/examples/iam/user-with-access-key/versions.tf
new file mode 100644
index 0000000..b81769a
--- /dev/null
+++ b/examples/iam/user-with-access-key/versions.tf
@@ -0,0 +1,13 @@
+terraform {
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 4.0"
+ }
+ }
+ required_version = "~> 1.0"
+}
+
+provider "aws" {
+ region = "eu-central-1"
+}
diff --git a/modules/iam/cloudfront-invalidation/README.md b/modules/iam/cloudfront-invalidation/README.md
new file mode 100644
index 0000000..b69244f
--- /dev/null
+++ b/modules/iam/cloudfront-invalidation/README.md
@@ -0,0 +1,30 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | >= 3.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | >= 3.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
+| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [cloudfront\_arns](#input\_cloudfront\_arns) | Cloudfront ARNs | `list(string)` | n/a | yes |
+| [name\_prefix](#input\_name\_prefix) | Prefix that will be prepended to resource names | `string` | n/a | yes |
+| [users](#input\_users) | Set of users names | `set(string)` | n/a | yes |
+
\ No newline at end of file
diff --git a/modules/iam/cloudfront-invalidation/main.tf b/modules/iam/cloudfront-invalidation/main.tf
new file mode 100644
index 0000000..0dfa047
--- /dev/null
+++ b/modules/iam/cloudfront-invalidation/main.tf
@@ -0,0 +1,20 @@
+data "aws_iam_policy_document" "this" {
+ statement {
+ actions = [
+ "cloudfront:CreateInvalidation",
+ ]
+
+ resources = var.cloudfront_arns
+ }
+}
+
+resource "aws_iam_policy" "this" {
+ name = "${var.name_prefix}-cdn-invalidation"
+ policy = data.aws_iam_policy_document.this.json
+}
+
+resource "aws_iam_policy_attachment" "this" {
+ name = "${var.name_prefix}-cdn-invalidation"
+ policy_arn = aws_iam_policy.this.arn
+ users = var.users
+}
diff --git a/modules/iam/cloudfront-invalidation/outputs.tf b/modules/iam/cloudfront-invalidation/outputs.tf
new file mode 100644
index 0000000..e69de29
diff --git a/modules/iam/cloudfront-invalidation/variables.tf b/modules/iam/cloudfront-invalidation/variables.tf
new file mode 100644
index 0000000..089c9de
--- /dev/null
+++ b/modules/iam/cloudfront-invalidation/variables.tf
@@ -0,0 +1,15 @@
+variable "name_prefix" {
+ type = string
+ description = "Prefix that will be prepended to resource names"
+}
+
+variable "cloudfront_arns" {
+ type = list(string)
+ description = "Cloudfront ARNs"
+}
+
+variable "users" {
+ type = set(string)
+ description = "Set of users names"
+}
+
diff --git a/modules/iam/cloudfront-invalidation/versions.tf b/modules/iam/cloudfront-invalidation/versions.tf
new file mode 100644
index 0000000..aa0082a
--- /dev/null
+++ b/modules/iam/cloudfront-invalidation/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 3.0"
+ }
+ }
+}
diff --git a/modules/iam/developers/README.md b/modules/iam/developers/README.md
new file mode 100644
index 0000000..bdaeca8
--- /dev/null
+++ b/modules/iam/developers/README.md
@@ -0,0 +1,34 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | >= 3.0 |
+| [random](#requirement\_random) | ~> 3.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | >= 3.0 |
+| [random](#provider\_random) | ~> 3.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_group) | resource |
+| [aws_iam_group_membership.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_group_membership) | resource |
+| [aws_iam_group_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_group_policy_attachment) | resource |
+| [aws_iam_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_user.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
+| [random_id.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
+| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [users](#input\_users) | Set of user names | `set(string)` | n/a | yes |
+
\ No newline at end of file
diff --git a/modules/iam/developers/main.tf b/modules/iam/developers/main.tf
new file mode 100644
index 0000000..17596b7
--- /dev/null
+++ b/modules/iam/developers/main.tf
@@ -0,0 +1,68 @@
+resource "random_id" "this" {
+ byte_length = 4
+
+ prefix = "account-access-"
+}
+
+
+resource "aws_iam_user" "this" {
+ for_each = var.users
+
+ name = each.value
+}
+
+data "aws_iam_policy_document" "this" {
+ statement {
+ sid = "AllowViewAccountInfo"
+ effect = "Allow"
+ actions = [
+ "iam:GetAccountPasswordPolicy",
+ "iam:GetAccountSummary"
+ ]
+ resources = ["*"]
+ }
+ statement {
+ sid = "AllowManageOwnPasswords"
+ effect = "Allow"
+ actions = [
+ "iam:ChangePassword",
+ "iam:GetUser"
+ ]
+ resources = ["arn:aws:iam::*:user/$${aws:username}"]
+ }
+ statement {
+ sid = "AllowManageOwnAccessKeys"
+ effect = "Allow"
+ actions = [
+ "iam:CreateAccessKey",
+ "iam:DeleteAccessKey",
+ "iam:ListAccessKeys",
+ "iam:UpdateAccessKey"
+ ]
+ resources = ["arn:aws:iam::*:user/$${aws:username}"]
+ }
+}
+
+resource "aws_iam_group" "this" {
+ name = random_id.this.hex
+}
+
+resource "aws_iam_group_membership" "this" {
+ for_each = var.users
+
+ name = random_id.this.hex
+
+ users = [each.value]
+
+ group = aws_iam_group.this.name
+}
+
+resource "aws_iam_group_policy_attachment" "this" {
+ group = aws_iam_group.this.name
+ policy_arn = aws_iam_policy.this.arn
+}
+
+resource "aws_iam_policy" "this" {
+ name = random_id.this.hex
+ policy = data.aws_iam_policy_document.this.json
+}
diff --git a/modules/iam/developers/outputs.tf b/modules/iam/developers/outputs.tf
new file mode 100644
index 0000000..e69de29
diff --git a/modules/iam/developers/variables.tf b/modules/iam/developers/variables.tf
new file mode 100644
index 0000000..c8e98f7
--- /dev/null
+++ b/modules/iam/developers/variables.tf
@@ -0,0 +1,5 @@
+variable "users" {
+ description = "Set of user names"
+
+ type = set(string)
+}
\ No newline at end of file
diff --git a/modules/iam/developers/versions.tf b/modules/iam/developers/versions.tf
new file mode 100644
index 0000000..88c98aa
--- /dev/null
+++ b/modules/iam/developers/versions.tf
@@ -0,0 +1,14 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 3.0"
+ }
+ random = {
+ source = "hashicorp/random"
+ version = "~> 3.0"
+ }
+ }
+}
diff --git a/modules/iam/ecr-pull-push/README.md b/modules/iam/ecr-pull-push/README.md
new file mode 100644
index 0000000..c37fc78
--- /dev/null
+++ b/modules/iam/ecr-pull-push/README.md
@@ -0,0 +1,37 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | >= 3.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | >= 3.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_policy.auth](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy.pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy.push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy_attachment.auth](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
+| [aws_iam_policy_attachment.pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
+| [aws_iam_policy_attachment.push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
+| [aws_iam_policy_document.auth](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+| [aws_iam_policy_document.pull](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+| [aws_iam_policy_document.push](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [ecr\_arn](#input\_ecr\_arn) | Elastic Container Registry Repository (ECR) ARN | `string` | n/a | yes |
+| [name\_prefix](#input\_name\_prefix) | Prefix that will be prepended to resource names | `string` | n/a | yes |
+| [pull\_users](#input\_pull\_users) | Set of user names | `set(string)` | `[]` | no |
+| [push\_users](#input\_push\_users) | Set of user names | `set(string)` | `[]` | no |
+
\ No newline at end of file
diff --git a/modules/iam/ecr-pull-push/main.tf b/modules/iam/ecr-pull-push/main.tf
new file mode 100644
index 0000000..10610a0
--- /dev/null
+++ b/modules/iam/ecr-pull-push/main.tf
@@ -0,0 +1,70 @@
+data "aws_iam_policy_document" "auth" {
+ statement {
+ actions = [
+ "ecr:GetAuthorizationToken"
+ ]
+
+ resources = ["*"]
+ }
+}
+
+data "aws_iam_policy_document" "pull" {
+ statement {
+ actions = [
+ "ecr:BatchGetImage",
+ "ecr:GetDownloadUrlForLayer",
+ "ecr:ListImages",
+ ]
+
+ resources = [var.ecr_arn]
+ }
+}
+
+data "aws_iam_policy_document" "push" {
+ statement {
+ actions = [
+ "ecr:BatchCheckLayerAvailability",
+ "ecr:CompleteLayerUpload",
+ "ecr:InitiateLayerUpload",
+ "ecr:PutImage",
+ "ecr:UploadLayerPart",
+ ]
+
+ resources = [var.ecr_arn]
+ }
+}
+
+resource "aws_iam_policy" "auth" {
+ name = "${var.name_prefix}-ecr-auth"
+ policy = data.aws_iam_policy_document.auth.json
+}
+
+resource "aws_iam_policy_attachment" "auth" {
+ name = "${var.name_prefix}-ecr-auth"
+ users = setunion(var.pull_users, var.push_users)
+ policy_arn = aws_iam_policy.auth.arn
+}
+
+resource "aws_iam_policy" "pull" {
+ name = "${var.name_prefix}-ecr-pull"
+ policy = data.aws_iam_policy_document.pull.json
+}
+
+resource "aws_iam_policy_attachment" "pull" {
+ count = length(var.pull_users) > 0 ? 1 : 0
+ name = "${var.name_prefix}-ecr-pull"
+ users = var.pull_users
+ policy_arn = aws_iam_policy.pull.arn
+}
+
+resource "aws_iam_policy" "push" {
+ name = "${var.name_prefix}-ecr-push"
+ policy = data.aws_iam_policy_document.push.json
+}
+
+resource "aws_iam_policy_attachment" "push" {
+ count = length(var.push_users) > 0 ? 1 : 0
+ name = "${var.name_prefix}-ecr-push"
+ users = var.push_users
+ policy_arn = aws_iam_policy.push.arn
+}
diff --git a/modules/iam/ecr-pull-push/outputs.tf b/modules/iam/ecr-pull-push/outputs.tf
new file mode 100644
index 0000000..e69de29
diff --git a/modules/iam/ecr-pull-push/variables.tf b/modules/iam/ecr-pull-push/variables.tf
new file mode 100644
index 0000000..98ee301
--- /dev/null
+++ b/modules/iam/ecr-pull-push/variables.tf
@@ -0,0 +1,21 @@
+variable "name_prefix" {
+ type = string
+ description = "Prefix that will be prepended to resource names"
+}
+
+variable "ecr_arn" {
+ type = string
+ description = "Elastic Container Registry Repository (ECR) ARN"
+}
+
+variable "pull_users" {
+ type = set(string)
+ description = "Set of user names"
+ default = []
+}
+
+variable "push_users" {
+ type = set(string)
+ description = "Set of user names"
+ default = []
+}
diff --git a/modules/iam/ecr-pull-push/versions.tf b/modules/iam/ecr-pull-push/versions.tf
new file mode 100644
index 0000000..aa0082a
--- /dev/null
+++ b/modules/iam/ecr-pull-push/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = ">= 3.0"
+ }
+ }
+}
diff --git a/modules/iam/ecs-deploy/README.md b/modules/iam/ecs-deploy/README.md
new file mode 100644
index 0000000..ed72e2b
--- /dev/null
+++ b/modules/iam/ecs-deploy/README.md
@@ -0,0 +1,30 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | ~> 4.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
+| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [name\_prefix](#input\_name\_prefix) | Prefix that will be prepended to resource names | `string` | n/a | yes |
+| [service\_arn](#input\_service\_arn) | Elastic Container Service (ECS) Service ARN | `string` | n/a | yes |
+| [users](#input\_users) | Set of user names | `set(string)` | n/a | yes |
+
\ No newline at end of file
diff --git a/modules/iam/ecs-deploy/main.tf b/modules/iam/ecs-deploy/main.tf
new file mode 100644
index 0000000..edbfc91
--- /dev/null
+++ b/modules/iam/ecs-deploy/main.tf
@@ -0,0 +1,30 @@
+data "aws_iam_policy_document" "this" {
+ statement {
+ actions = [
+ "ecs:DescribeTaskDefinition",
+ "ecs:RegisterTaskDefinition",
+ ]
+
+ resources = ["*"]
+ }
+
+ statement {
+ actions = [
+ "ecs:DescribeServices",
+ "ecs:UpdateService",
+ ]
+
+ resources = [var.service_arn]
+ }
+}
+
+resource "aws_iam_policy" "this" {
+ name = "${var.name_prefix}-ecs-deploy"
+ policy = data.aws_iam_policy_document.this.json
+}
+
+resource "aws_iam_policy_attachment" "this" {
+ name = "${var.name_prefix}-ecs-deploy"
+ users = var.users
+ policy_arn = aws_iam_policy.this.arn
+}
diff --git a/modules/iam/ecs-deploy/outputs.tf b/modules/iam/ecs-deploy/outputs.tf
new file mode 100644
index 0000000..e69de29
diff --git a/modules/iam/ecs-deploy/variables.tf b/modules/iam/ecs-deploy/variables.tf
new file mode 100644
index 0000000..0c59f86
--- /dev/null
+++ b/modules/iam/ecs-deploy/variables.tf
@@ -0,0 +1,14 @@
+variable "name_prefix" {
+ type = string
+ description = "Prefix that will be prepended to resource names"
+}
+
+variable "service_arn" {
+ type = string
+ description = "Elastic Container Service (ECS) Service ARN"
+}
+
+variable "users" {
+ type = set(string)
+ description = "Set of user names"
+}
diff --git a/modules/iam/ecs-deploy/versions.tf b/modules/iam/ecs-deploy/versions.tf
new file mode 100644
index 0000000..329d64d
--- /dev/null
+++ b/modules/iam/ecs-deploy/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+}
diff --git a/modules/iam/s3-read-write/README.md b/modules/iam/s3-read-write/README.md
new file mode 100644
index 0000000..2794d62
--- /dev/null
+++ b/modules/iam/s3-read-write/README.md
@@ -0,0 +1,30 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | ~> 4.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
+| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [bucket\_arn](#input\_bucket\_arn) | S3 Bucket ARN | `string` | n/a | yes |
+| [name\_prefix](#input\_name\_prefix) | Prefix that will be prepended to resource names | `string` | n/a | yes |
+| [users](#input\_users) | Set of users names | `set(string)` | n/a | yes |
+
\ No newline at end of file
diff --git a/modules/iam/s3-read-write/main.tf b/modules/iam/s3-read-write/main.tf
new file mode 100644
index 0000000..2742db2
--- /dev/null
+++ b/modules/iam/s3-read-write/main.tf
@@ -0,0 +1,41 @@
+data "aws_iam_policy_document" "this" {
+ statement {
+ actions = [
+ "s3:DeleteObjectTagging",
+ "s3:PutObject",
+ "s3:GetObjectAcl",
+ "s3:GetObject",
+ "s3:GetObjectTagging",
+ "s3:PutObjectTagging",
+ "s3:DeleteObject",
+ "s3:PutObjectAcl"
+ ]
+
+ resources = [
+ "${var.bucket_arn}/*"
+ ]
+ }
+
+ statement {
+ actions = [
+ "s3:GetBucketTagging",
+ "s3:ListBucket",
+ "s3:GetBucketLocation"
+ ]
+
+ resources = [
+ var.bucket_arn
+ ]
+ }
+}
+
+resource "aws_iam_policy" "this" {
+ name = "${var.name_prefix}-s3-read-write"
+ policy = data.aws_iam_policy_document.this.json
+}
+
+resource "aws_iam_policy_attachment" "this" {
+ name = "${var.name_prefix}-s3-read-write"
+ users = var.users
+ policy_arn = aws_iam_policy.this.arn
+}
diff --git a/modules/iam/s3-read-write/outputs.tf b/modules/iam/s3-read-write/outputs.tf
new file mode 100644
index 0000000..e69de29
diff --git a/modules/iam/s3-read-write/variables.tf b/modules/iam/s3-read-write/variables.tf
new file mode 100644
index 0000000..ee27fdc
--- /dev/null
+++ b/modules/iam/s3-read-write/variables.tf
@@ -0,0 +1,14 @@
+variable "name_prefix" {
+ type = string
+ description = "Prefix that will be prepended to resource names"
+}
+
+variable "bucket_arn" {
+ type = string
+ description = "S3 Bucket ARN"
+}
+
+variable "users" {
+ type = set(string)
+ description = "Set of users names"
+}
diff --git a/modules/iam/s3-read-write/versions.tf b/modules/iam/s3-read-write/versions.tf
new file mode 100644
index 0000000..329d64d
--- /dev/null
+++ b/modules/iam/s3-read-write/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+}
diff --git a/modules/iam/secrets-manager/README.md b/modules/iam/secrets-manager/README.md
new file mode 100644
index 0000000..34e0468
--- /dev/null
+++ b/modules/iam/secrets-manager/README.md
@@ -0,0 +1,34 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | ~> 4.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_policy.read_secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy.write_secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy_attachment.read_secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
+| [aws_iam_policy_attachment.write_secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy_attachment) | resource |
+| [aws_iam_policy_document.read_secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+| [aws_iam_policy_document.write_secret](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [name\_prefix](#input\_name\_prefix) | Prefix that will be prepended to resource names | `string` | n/a | yes |
+| [read\_users](#input\_read\_users) | Set of users names | `set(string)` | `[]` | no |
+| [secrets](#input\_secrets) | Set of Secret Manager Secrets ARNs | `set(string)` | n/a | yes |
+| [write\_users](#input\_write\_users) | Set of users names | `set(string)` | `[]` | no |
+
\ No newline at end of file
diff --git a/modules/iam/secrets-manager/main.tf b/modules/iam/secrets-manager/main.tf
new file mode 100644
index 0000000..2ca083d
--- /dev/null
+++ b/modules/iam/secrets-manager/main.tf
@@ -0,0 +1,52 @@
+data "aws_iam_policy_document" "read_secret" {
+ statement {
+ actions = [
+ "secretsmanager:ListSecrets"
+ ]
+
+ resources = ["*"]
+ }
+
+ statement {
+ actions = [
+ "secretsmanager:DescribeSecret",
+ "secretsmanager:GetSecretValue",
+ "secretsmanager:ListSecretVersionIds",
+ ]
+
+ resources = var.secrets
+ }
+}
+
+data "aws_iam_policy_document" "write_secret" {
+ statement {
+ actions = [
+ "secretsmanager:PutSecretValue",
+ ]
+
+ resources = var.secrets
+ }
+}
+
+resource "aws_iam_policy" "read_secret" {
+ name = "${var.name_prefix}-read-secret"
+ policy = data.aws_iam_policy_document.read_secret.json
+}
+
+resource "aws_iam_policy_attachment" "read_secret" {
+ name = "${var.name_prefix}-read-secret"
+ users = setunion(var.read_users, var.write_users)
+ policy_arn = aws_iam_policy.read_secret.arn
+}
+
+resource "aws_iam_policy" "write_secret" {
+ name = "${var.name_prefix}-write-secret"
+ policy = data.aws_iam_policy_document.write_secret.json
+}
+
+resource "aws_iam_policy_attachment" "write_secret" {
+ count = length(var.write_users) > 0 ? 1 : 0
+ name = "${var.name_prefix}-write-secret"
+ users = var.write_users
+ policy_arn = aws_iam_policy.write_secret.arn
+}
diff --git a/modules/iam/secrets-manager/outputs.tf b/modules/iam/secrets-manager/outputs.tf
new file mode 100644
index 0000000..e69de29
diff --git a/modules/iam/secrets-manager/variables.tf b/modules/iam/secrets-manager/variables.tf
new file mode 100644
index 0000000..d7bc2ce
--- /dev/null
+++ b/modules/iam/secrets-manager/variables.tf
@@ -0,0 +1,21 @@
+variable "name_prefix" {
+ type = string
+ description = "Prefix that will be prepended to resource names"
+}
+
+variable "secrets" {
+ type = set(string)
+ description = "Set of Secret Manager Secrets ARNs"
+}
+
+variable "read_users" {
+ type = set(string)
+ description = "Set of users names"
+ default = []
+}
+
+variable "write_users" {
+ type = set(string)
+ description = "Set of users names"
+ default = []
+}
diff --git a/modules/iam/secrets-manager/versions.tf b/modules/iam/secrets-manager/versions.tf
new file mode 100644
index 0000000..329d64d
--- /dev/null
+++ b/modules/iam/secrets-manager/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+}
diff --git a/modules/iam/ssm/README.md b/modules/iam/ssm/README.md
new file mode 100644
index 0000000..5045448
--- /dev/null
+++ b/modules/iam/ssm/README.md
@@ -0,0 +1,24 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [kms\_arn](#input\_kms\_arn) | KMS key to encrypt session | `string` | n/a | yes |
+| [ssm\_document\_arn](#input\_ssm\_document\_arn) | SSM document ARN to use by session | `string` | n/a | yes |
+| [ssm\_tag\_key](#input\_ssm\_tag\_key) | SSM tag key used for accessing EC2 | `string` | `"SSMAccess"` | no |
+| [ssm\_tag\_value](#input\_ssm\_tag\_value) | SSM tag value used for accessing EC2 | `string` | `"true"` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [ssm\_access\_policy\_rendered](#output\_ssm\_access\_policy\_rendered) | SSM policy to attach to IAM user/role that allows access EC2 |
+| [ssm\_policy\_rendered](#output\_ssm\_policy\_rendered) | SSM policy to attach to EC2 role |
+
\ No newline at end of file
diff --git a/modules/iam/ssm/main.tf b/modules/iam/ssm/main.tf
new file mode 100644
index 0000000..0706609
--- /dev/null
+++ b/modules/iam/ssm/main.tf
@@ -0,0 +1,12 @@
+locals {
+ ssm_ec2_policy = templatefile("${path.module}/tpl/ssm_policy.json", {
+ kms_arn = var.kms_arn
+ })
+
+ ssm_access_policy = templatefile("${path.module}/tpl/ssm_access_policy.json", {
+ kms_arn = var.kms_arn
+ ec2_tag_key = var.ssm_tag_key
+ ec2_tag_value = var.ssm_tag_value
+ document_arn = var.ssm_document_arn
+ })
+}
diff --git a/modules/iam/ssm/outputs.tf b/modules/iam/ssm/outputs.tf
new file mode 100644
index 0000000..37ee1d6
--- /dev/null
+++ b/modules/iam/ssm/outputs.tf
@@ -0,0 +1,9 @@
+output "ssm_policy_rendered" {
+ description = "SSM policy to attach to EC2 role"
+ value = local.ssm_ec2_policy
+}
+
+output "ssm_access_policy_rendered" {
+ description = "SSM policy to attach to IAM user/role that allows access EC2"
+ value = local.ssm_access_policy
+}
diff --git a/modules/iam/ssm/tpl/ssm_access_policy.json b/modules/iam/ssm/tpl/ssm_access_policy.json
new file mode 100644
index 0000000..649f075
--- /dev/null
+++ b/modules/iam/ssm/tpl/ssm_access_policy.json
@@ -0,0 +1,63 @@
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "ssm:DescribeSessions",
+ "ssm:GetConnectionStatus",
+ "ssm:DescribeInstanceProperties",
+ "ssm:DescribeInstanceInformation",
+ "ec2:DescribeInstances"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Action": [
+ "ssm:StartSession"
+ ],
+ "Resource": [
+ "arn:aws:ec2:*:*:instance/*"
+ ],
+ "Effect": "Allow",
+ "Condition": {
+ "StringEquals": {
+ "ssm:resourceTag/${ec2_tag_key}": [
+ "${ec2_tag_value}"
+ ]
+ }
+ }
+ },
+ {
+ "Action": [
+ "ssm:StartSession"
+ ],
+ "Resource": [
+ "${document_arn}"
+ ],
+ "Effect": "Allow",
+ "Condition": {
+ "BoolIfExists": {
+ "ssm:SessionDocumentAccessCheck": "true"
+ }
+ }
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "ssm:TerminateSession",
+ "ssm:ResumeSession"
+ ],
+ "Resource": [
+ "arn:aws:ssm:*:*:session/$${aws:username}-*"
+ ]
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "kms:GenerateDataKey"
+ ],
+ "Resource": "${kms_arn}"
+ }
+ ]
+}
diff --git a/modules/iam/ssm/tpl/ssm_policy.json b/modules/iam/ssm/tpl/ssm_policy.json
new file mode 100644
index 0000000..7582c75
--- /dev/null
+++ b/modules/iam/ssm/tpl/ssm_policy.json
@@ -0,0 +1,36 @@
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "ssm:UpdateInstanceInformation"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "ssmmessages:CreateControlChannel",
+ "ssmmessages:CreateDataChannel",
+ "ssmmessages:OpenControlChannel",
+ "ssmmessages:OpenDataChannel"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "s3:GetEncryptionConfiguration"
+ ],
+ "Resource": "*"
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "kms:Decrypt"
+ ],
+ "Resource": "${kms_arn}"
+ }
+ ]
+}
diff --git a/modules/iam/ssm/variables.tf b/modules/iam/ssm/variables.tf
new file mode 100644
index 0000000..552d06e
--- /dev/null
+++ b/modules/iam/ssm/variables.tf
@@ -0,0 +1,23 @@
+variable "kms_arn" {
+ type = string
+ description = "KMS key to encrypt session"
+}
+
+variable "ssm_document_arn" {
+ type = string
+ description = "SSM document ARN to use by session"
+}
+
+# optional
+
+variable "ssm_tag_key" {
+ type = string
+ description = "SSM tag key used for accessing EC2"
+ default = "SSMAccess"
+}
+
+variable "ssm_tag_value" {
+ type = string
+ description = "SSM tag value used for accessing EC2"
+ default = "true"
+}
diff --git a/modules/iam/ssm/versions.tf b/modules/iam/ssm/versions.tf
new file mode 100644
index 0000000..329d64d
--- /dev/null
+++ b/modules/iam/ssm/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+}
diff --git a/modules/iam/user-with-access-key/README.md b/modules/iam/user-with-access-key/README.md
new file mode 100644
index 0000000..80207b8
--- /dev/null
+++ b/modules/iam/user-with-access-key/README.md
@@ -0,0 +1,41 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 4.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | ~> 4.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_access_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
+| [aws_iam_user.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
+| [aws_iam_user_group_membership.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_group_membership) | resource |
+| [aws_iam_user_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy_attachment) | resource |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [groups](#input\_groups) | List of groups to attach | `list(string)` | `[]` | no |
+| [name](#input\_name) | User name | `string` | n/a | yes |
+| [policies](#input\_policies) | List of policies to attach | `list(string)` | `[]` | no |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [access\_key\_as\_envs](#output\_access\_key\_as\_envs) | User access key map containing AWS\_ACCESS\_KEY\_ID and AWS\_SECRET\_ACCESS\_KEY. |
+| [arn](#output\_arn) | User ARN. |
+| [key\_id](#output\_key\_id) | Access key ID. |
+| [key\_secret](#output\_key\_secret) | Access secret access key. |
+| [name](#output\_name) | User name. |
+
\ No newline at end of file
diff --git a/modules/iam/user-with-access-key/main.tf b/modules/iam/user-with-access-key/main.tf
new file mode 100644
index 0000000..2fe14e7
--- /dev/null
+++ b/modules/iam/user-with-access-key/main.tf
@@ -0,0 +1,33 @@
+resource "aws_iam_user" "this" {
+ name = var.name
+}
+
+resource "aws_iam_access_key" "this" {
+ user = aws_iam_user.this.name
+
+ depends_on = [
+ aws_iam_user.this,
+ ]
+}
+
+resource "aws_iam_user_group_membership" "this" {
+ count = length(var.groups) > 0 ? 1 : 0
+
+ user = aws_iam_user.this.name
+ groups = var.groups
+
+ depends_on = [
+ aws_iam_user.this,
+ ]
+}
+
+resource "aws_iam_user_policy_attachment" "this" {
+ count = length(var.policies)
+
+ user = aws_iam_user.this.name
+ policy_arn = var.policies[count.index]
+
+ depends_on = [
+ aws_iam_user.this,
+ ]
+}
diff --git a/modules/iam/user-with-access-key/outputs.tf b/modules/iam/user-with-access-key/outputs.tf
new file mode 100644
index 0000000..a7edba5
--- /dev/null
+++ b/modules/iam/user-with-access-key/outputs.tf
@@ -0,0 +1,30 @@
+output "name" {
+ description = "User name."
+ value = aws_iam_user.this.name
+}
+
+output "arn" {
+ description = "User ARN."
+ value = aws_iam_user.this.arn
+}
+
+output "access_key_as_envs" {
+ description = "User access key map containing AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY."
+ value = {
+ AWS_ACCESS_KEY_ID = aws_iam_access_key.this.id
+ AWS_SECRET_ACCESS_KEY = aws_iam_access_key.this.secret
+ }
+ sensitive = true
+}
+
+output "key_id" {
+ description = "Access key ID."
+ value = aws_iam_access_key.this.id
+ sensitive = true
+}
+
+output "key_secret" {
+ description = "Access secret access key."
+ value = aws_iam_access_key.this.secret
+ sensitive = true
+}
diff --git a/modules/iam/user-with-access-key/variables.tf b/modules/iam/user-with-access-key/variables.tf
new file mode 100644
index 0000000..cc36ee1
--- /dev/null
+++ b/modules/iam/user-with-access-key/variables.tf
@@ -0,0 +1,16 @@
+variable "name" {
+ type = string
+ description = "User name"
+}
+
+variable "groups" {
+ type = list(string)
+ description = "List of groups to attach"
+ default = []
+}
+
+variable "policies" {
+ type = list(string)
+ description = "List of policies to attach"
+ default = []
+}
diff --git a/modules/iam/user-with-access-key/versions.tf b/modules/iam/user-with-access-key/versions.tf
new file mode 100644
index 0000000..329d64d
--- /dev/null
+++ b/modules/iam/user-with-access-key/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 4.0"
+ }
+ }
+}