diff --git a/terraform/modules/buckets/.gitignore b/terraform/modules/buckets/.gitignore new file mode 100644 index 0000000..df50a6a --- /dev/null +++ b/terraform/modules/buckets/.gitignore @@ -0,0 +1,7 @@ +*.swp +.terraform* +main.tfvars +terraform.tfstate* +plan.tfplan +errored.tfstate +!.terraform-docs.yml diff --git a/terraform/modules/buckets/.terraform-docs.yml b/terraform/modules/buckets/.terraform-docs.yml new file mode 100644 index 0000000..73058d1 --- /dev/null +++ b/terraform/modules/buckets/.terraform-docs.yml @@ -0,0 +1,47 @@ +formatter: "md table" # this is required + +version: "" + +header-from: docs/header.md +footer-from: "" + +recursive: + enabled: false + path: modules + +sections: + hide: [] + show: [] + +content: "" + +output: + file: "" + mode: inject + template: |- + + {{ .Content }} + + +output-values: + enabled: false + from: "" + +sort: + enabled: true + by: name + +settings: + anchor: true + color: true + default: true + description: false + escape: true + hide-empty: false + html: true + indent: 2 + lockfile: true + read-comments: true + required: true + sensitive: true + type: true diff --git a/terraform/modules/buckets/README.md b/terraform/modules/buckets/README.md new file mode 100644 index 0000000..227202a --- /dev/null +++ b/terraform/modules/buckets/README.md @@ -0,0 +1,91 @@ + +## Description du module + +Ce module a pour but de gérer les applications et leur ressources associées dans le cloud public Scaleway. + +## Fonctionnement du module + +- Ce module prend en charge la gestion des ressources suivantes : + - Les applications, groupes et policies de l'IAM Scaleway. + - Les buckets S3 et de leur policy associée. + - Les file d'attente de type SQS et leurs identifiants associés. + +### Fonctionnement bucket S3 + +#### Pré-requis + +- Une liste de bucket est déclarée au sein de l'application. +- Pour déclarer des règles de cycle de vie (lifecycle\_rules), au moins expiration\_days ou le couple transition\_days et transition\_sc doivent être déclarés. + +#### Fonctionnement + +- Pour chaque bucket de la liste buckets\_list, une resource va être déclarée. Dans cette ressource, une lifecycle\_rule va être déclarée pour chaque membre de la liste de lifecycle\_rule. +- Pour chaque bucket de la liste buckets\_list, une policy est attachée et contient 3 sections : + - Une section pour autoriser l'application principale à accéder au bucket. + - Une section pour donner accès aux user\_id et application\_id des administrateurs. + - Une section pour donner accès à d'autres user\_id pour une application tierce. + +### Fonctionnement SQS + +#### Pré-requis + +- Avoir activé le module SQS dans l'interface Scaleway -> Messaging. +- Une liste de queue est déclarée au sein de l'application. + +#### Informations + +- On utilise une resource de type scaleway\_mnq\_sqs\_credentials.admin\_creds par projet. En effet, en lui donnant uniquement le droit "can\_manage", elle peut créer, supprimer et modifier des queues mais pas accéder à leur contenu. +- En parallèle, on créé un jeu d'identifiant par application et par queue qui ne disposent que des droits de publication/réception. + +## Requirements + +| Name | Version | +|------|---------| +| [scaleway](#requirement\_scaleway) | >= 2.35.0 | + +## Providers + +| Name | Version | +|------|---------| +| [scaleway](#provider\_scaleway) | >= 2.35.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [scaleway_iam_api_key.keys](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/iam_api_key) | resource | +| [scaleway_iam_application.apps](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/iam_application) | resource | +| [scaleway_iam_group.groups](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/iam_group) | resource | +| [scaleway_iam_policy.group_policies](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/iam_policy) | resource | +| [scaleway_object_bucket.s3_buckets](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/object_bucket) | resource | +| [scaleway_object_bucket_policy.s3_policies](https://registry.terraform.io/providers/scaleway/scaleway/latest/docs/resources/object_bucket_policy) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [admins\_user\_id](#input\_admins\_user\_id) | List of s3 admin user's ID | `list(string)` | `[]` | no | +| [app\_desc](#input\_app\_desc) | Application's description | `string` | `""` | no | +| [app\_name](#input\_app\_name) | Name of the application | `string` | `"changeme"` | no | +| [app\_tags](#input\_app\_tags) | Application's tags | `map(string)` | `{}` | no | +| [buckets\_list](#input\_buckets\_list) | List of the application's buckets |
list(object({
bucket_name = string
bucket_region = optional(string)
bucket_versioning = optional(bool)
bucket_tags = optional(map(string))
bucket_policy_actions = optional(list(string))
bucket_lifecycle_rules = optional(list(object({
id = string
enabled = bool
prefix = optional(string)
expiration_days = optional(number)
transition_days = optional(number)
transition_sc = optional(string)
tags = optional(map(string))
})))
other_app_access = optional(list(string))
other_app_policy_actions= optional(list(string))
}))
| n/a | yes | +| [env](#input\_env) | App's environment (dev/stg/prd/inf) | `string` | `"dev"` | no | +| [policy\_permissions](#input\_policy\_permissions) | Policy permissions for app | `list(string)` | `[]` | no | +| [project\_id](#input\_project\_id) | App's project ID | `string` | `"changeme"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [api\_access\_key](#output\_api\_access\_key) | App access key | +| [api\_secret\_key](#output\_api\_secret\_key) | App secret key | +| [app\_desc](#output\_app\_desc) | Description of the application | +| [app\_id](#output\_app\_id) | ID of the application | +| [app\_name](#output\_app\_name) | Name of the application | +| [bucket\_ID](#output\_bucket\_ID) | ID of the bucket | +| [bucket\_endpoint](#output\_bucket\_endpoint) | Bucket's endpoint | + \ No newline at end of file diff --git a/terraform/modules/buckets/buckets.tf b/terraform/modules/buckets/buckets.tf new file mode 100644 index 0000000..6d85ce6 --- /dev/null +++ b/terraform/modules/buckets/buckets.tf @@ -0,0 +1,86 @@ +resource "scaleway_object_bucket" "s3_buckets" { + for_each = (var.buckets_list == null) ? {} : { for b in var.buckets_list : b.bucket_name => b } + + name = each.value.bucket_name + tags = each.value.bucket_tags + region = each.value.bucket_region + project_id = var.project_id + versioning { + enabled = each.value.bucket_versioning + } + + /* Dans cette section, on ajoute un bloc lifecycle_rule pour chaque + élément présent dans la liste lifecycle_rules de l'objet buckets. + */ + dynamic "lifecycle_rule" { + for_each = each.value.bucket_lifecycle_rules + content { + id = lifecycle_rule.value["id"] + prefix = lifecycle_rule.value["prefix"] + enabled = lifecycle_rule.value["enabled"] + tags = lifecycle_rule.value["tags"] + /* On ajoute les blocs expiration ou transition en fonction + de la présence ou non des variables expiration_days, + transition_days et transition_sc. Au moins l'un de ces blocs + est obligatoire pour que la règle soit valide. + */ + dynamic "expiration" { + for_each = lifecycle_rule.value["expiration_days"] == null ? [] : [1] + content { + days = lifecycle_rule.value["expiration_days"] + } + } + dynamic "transition" { + for_each = (lifecycle_rule.value["transition_days"] == null) && (lifecycle_rule.value["transition_sc"] == null) ? [] : [1] + content { + days = lifecycle_rule.value["transition_days"] + storage_class = lifecycle_rule.value["transition_sc"] + } + } + } + } + + depends_on = [ + scaleway_iam_api_key.keys + ] +} + +resource "scaleway_object_bucket_policy" "s3_policies" { + for_each = (var.buckets_list == null) ? {} : { for b in var.buckets_list : b.bucket_name => b } + + bucket = each.value.bucket_name + policy = jsonencode({ + Version = "2023-04-17", + Id = "${each.value.bucket_name}", + Statement = [ + { + Sid = "RW-${each.value.bucket_name}", + Effect = "Allow", + Principal = { + SCW = "application_id:${scaleway_iam_application.apps.id}" + }, + Action = "${each.value.bucket_policy_actions}", + Resource = [ + "${each.value.bucket_name}", + "${each.value.bucket_name}/*" + ], + }, + { + Sid = "Admin-${each.value.bucket_name}", + Effect = "Allow", + Principal = { + SCW = var.admins_user_id + }, + Action = "s3:*", + Resource = [ + "${each.value.bucket_name}", + "${each.value.bucket_name}/*" + ], + } + ] + }) + + depends_on = [ + scaleway_object_bucket.s3_buckets + ] +} diff --git a/terraform/modules/buckets/docs/header.md b/terraform/modules/buckets/docs/header.md new file mode 100644 index 0000000..a95a97e --- /dev/null +++ b/terraform/modules/buckets/docs/header.md @@ -0,0 +1,37 @@ +## Description du module + +Ce module a pour but de gérer les applications et leur ressources associées dans le cloud public Scaleway. + +## Fonctionnement du module + +- Ce module prend en charge la gestion des ressources suivantes : + - Les applications, groupes et policies de l'IAM Scaleway. + - Les buckets S3 et de leur policy associée. + - Les file d'attente de type SQS et leurs identifiants associés. + +### Fonctionnement bucket S3 + +#### Pré-requis + +- Une liste de bucket est déclarée au sein de l'application. +- Pour déclarer des règles de cycle de vie (lifecycle_rules), au moins expiration_days ou le couple transition_days et transition_sc doivent être déclarés. + +#### Fonctionnement + +- Pour chaque bucket de la liste buckets_list, une resource va être déclarée. Dans cette ressource, une lifecycle_rule va être déclarée pour chaque membre de la liste de lifecycle_rule. +- Pour chaque bucket de la liste buckets_list, une policy est attachée et contient 3 sections : + - Une section pour autoriser l'application principale à accéder au bucket. + - Une section pour donner accès aux user_id et application_id des administrateurs. + - Une section pour donner accès à d'autres user_id pour une application tierce. + +### Fonctionnement SQS + +#### Pré-requis + +- Avoir activé le module SQS dans l'interface Scaleway -> Messaging. +- Une liste de queue est déclarée au sein de l'application. + +#### Informations + +- On utilise une resource de type scaleway_mnq_sqs_credentials.admin_creds par projet. En effet, en lui donnant uniquement le droit "can_manage", elle peut créer, supprimer et modifier des queues mais pas accéder à leur contenu. +- En parallèle, on créé un jeu d'identifiant par application et par queue qui ne disposent que des droits de publication/réception. diff --git a/terraform/modules/buckets/iam.tf b/terraform/modules/buckets/iam.tf new file mode 100644 index 0000000..55076b0 --- /dev/null +++ b/terraform/modules/buckets/iam.tf @@ -0,0 +1,41 @@ +resource "scaleway_iam_application" "apps" { + name = "${var.app_name}-${var.env}" + description = "${var.app_desc} env : ${var.env}" +} + +resource "scaleway_iam_api_key" "keys" { + application_id = scaleway_iam_application.apps.id + description = "${var.app_name}-${var.env} api key" + default_project_id = var.project_id + + depends_on = [ + scaleway_iam_application.apps + ] +} + +resource "scaleway_iam_group" "groups" { + name = "group-${var.app_name}-${var.env}" + description = "${var.app_name} IAM group for env ${var.env}" + + application_ids = [ + scaleway_iam_application.apps.id + ] + + depends_on = [ + scaleway_iam_application.apps + ] +} + +resource scaleway_iam_policy "group_policies" { + name = "policy-${var.app_name}-${var.env}" + description = "${var.app_name} policy for group ${scaleway_iam_group.groups.name} in env ${var.env}" + group_id = scaleway_iam_group.groups.id + rule { + project_ids = [var.project_id] + permission_set_names = var.policy_permissions + } + + depends_on = [ + scaleway_iam_group.groups + ] +} diff --git a/terraform/modules/buckets/main.tf b/terraform/modules/buckets/main.tf new file mode 100644 index 0000000..2d43ee1 --- /dev/null +++ b/terraform/modules/buckets/main.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + scaleway = { + source = "scaleway/scaleway" + version = ">= 2.35.0" + } + } +} diff --git a/terraform/modules/buckets/outputs.tf b/terraform/modules/buckets/outputs.tf new file mode 100644 index 0000000..ffe3b46 --- /dev/null +++ b/terraform/modules/buckets/outputs.tf @@ -0,0 +1,43 @@ +############# +# APP OUTPUT +############# + + +output "app_name" { + description = "Name of the application" + value = scaleway_iam_application.apps.name +} + +output "app_id" { + description = "ID of the application" + value = scaleway_iam_application.apps.id +} + +output "app_desc" { + description = "Description of the application" + value = scaleway_iam_application.apps.description +} + +output "api_access_key" { + description = "App access key" + value = scaleway_iam_api_key.keys.access_key +} + +output "api_secret_key" { + description = "App secret key" + value = scaleway_iam_api_key.keys.secret_key +} + +############## +# BUCKET OUTPUT +############## + +output "bucket_ID" { + description = "ID of the bucket" + value = [ for b in scaleway_object_bucket.s3_buckets: b.id ] +} + +output "bucket_endpoint" { + description = "Bucket's endpoint" + value = [ for b in scaleway_object_bucket.s3_buckets: b.endpoint ] +} diff --git a/terraform/modules/buckets/variables.tf b/terraform/modules/buckets/variables.tf new file mode 100644 index 0000000..bd8cb9b --- /dev/null +++ b/terraform/modules/buckets/variables.tf @@ -0,0 +1,77 @@ +################### +# GLOBAL VARIABLES +################### + +variable "project_id" { + description = "App's project ID" + type = string + default = "changeme" +} +################### +# APP VARIABLES +################### + +variable "app_name" { + description = "Name of the application" + type = string + default = "changeme" +} + +variable "app_desc" { + description = "Application's description" + type = string + default = "" +} + +variable "app_tags" { + description = "Application's tags" + type = map(string) + default = {} +} + +variable "env" { + description = "App's environment (dev/stg/prd/inf)" + type = string + default = "dev" +} + +variable "policy_permissions" { + description = "Policy permissions for app" + type = list(string) + default = [] +} + +################### +# BUCKETS VARIABLE +################### + +variable "buckets_list" { + description = "List of the application's buckets" + type = list(object({ + bucket_name = string + bucket_region = optional(string) + bucket_versioning = optional(bool) + bucket_tags = optional(map(string)) + bucket_policy_actions = optional(list(string)) + bucket_lifecycle_rules = optional(list(object({ + id = string + enabled = bool + prefix = optional(string) + expiration_days = optional(number) + transition_days = optional(number) + transition_sc = optional(string) + tags = optional(map(string)) + }))) + other_app_access = optional(list(string)) + other_app_policy_actions= optional(list(string)) + })) +} + + +# 09/01/2024 - Pas possible de mettre des group_id comme principal +# cf https://feature-request.scaleway.com/posts/714/bucket-policy-with-group_id +variable "admins_user_id" { + description = "List of s3 admin user's ID" + type = list(string) + default = [] +}