Page MenuHomeDevCentral

D4206.diff
No OneTemporary

D4206.diff

diff --git a/terraform/ovh-ops-backups/locals.tf b/terraform/ovh-ops-backups/locals.tf
new file mode 100644
--- /dev/null
+++ b/terraform/ovh-ops-backups/locals.tf
@@ -0,0 +1,130 @@
+# -------------------------------------------------------------
+# Terraform :: OVH :: Public cloud :: ops-backups :: Storage
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: BSD-2-Clause
+# Description: Create object storage bucket for backups.
+# Provider: OVH + Vault / OpenBao
+# Target: OVH Public Cloud > Nasqueron :: Operations :: Backups
+# complector.nasqueron.drake (Vault)
+# -------------------------------------------------------------
+
+locals {
+ default_tags = {
+ group = "operations"
+ role = "backup"
+ encryption = "client-side"
+ privacy_level = "sensible"
+ }
+
+ backup_containers = {
+ amaris = {
+ container_name = "nasqueron-backups-amaris"
+ purpose = "Main backup container"
+
+ tags = local.default_tags
+
+ # Each server should get access
+ # For databases servers, prefixes are by cluster.
+ clients = {
+ windriver = {
+ prefixes = [
+ "windriver",
+ ]
+ }
+
+ db-a-001 = {
+ prefixes = [
+ "db-a",
+ ]
+ }
+
+ db-b-001 = {
+ prefixes = [
+ "db-b",
+ ]
+ }
+
+ dns-001 = {
+ prefixes = [
+ "dns-001",
+ ]
+ }
+
+ docker-002 = {
+ prefixes = [
+ "docker-002",
+ ]
+ }
+
+ dwellers = {
+ prefixes = [
+ "dwellers",
+ ]
+ }
+
+ hervil = {
+ prefixes = [
+ "hervil",
+ ]
+ }
+
+ router-001 = {
+ prefixes = [
+ "router-intranought",
+ ]
+ }
+
+ router-002 = {
+ prefixes = [
+ "router-intranought",
+ ]
+ }
+
+ router-003 = {
+ prefixes = [
+ "router-intranought",
+ ]
+ }
+
+ web-001 = {
+ prefixes = [
+ "web-001",
+ ]
+ }
+ }
+ }
+
+ darak = {
+ container_name = "nasqueron-backups-darak"
+ purpose = "Dereckson backups"
+
+ tags = merge(local.default_tags, {
+ group = "user-dereckson"
+ })
+
+ clients = {
+ windriver = {
+ prefixes = [
+ "windriver-home",
+ ]
+ }
+ }
+ }
+
+ vakor = {
+ container_name = "nasqueron-backups-vakor"
+ purpose = "Vault backups"
+
+ tags = local.default_tags
+
+ clients = {
+ complector = {
+ prefixes = [
+ "complector",
+ ]
+ }
+ }
+ }
+ }
+}
diff --git a/terraform/ovh-ops-backups/modules/object_storage_project_user/main.tf b/terraform/ovh-ops-backups/modules/object_storage_project_user/main.tf
new file mode 100644
--- /dev/null
+++ b/terraform/ovh-ops-backups/modules/object_storage_project_user/main.tf
@@ -0,0 +1,115 @@
+# -------------------------------------------------------------
+# Terraform :: OVH :: Public cloud :: ops-backups :: Project user
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: BSD-2-Clause
+# Description: Create user with access to object storage container
+# for backups in specified prefix.
+# Provider: OVH
+# -------------------------------------------------------------
+
+# -------------------------------------------------------------
+# Project user
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+resource "ovh_cloud_project_user" "user" {
+ service_name = var.service_name
+ description = var.description
+}
+
+resource "ovh_cloud_project_user_s3_credential" "s3_credentials" {
+ service_name = var.service_name
+ user_id = ovh_cloud_project_user.user.id
+}
+
+# -------------------------------------------------------------
+# Policy for the user
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+locals {
+ # Normalize prefixes: remove leading/trailing slashes, ignore empty values.
+ normalized_prefixes = distinct([
+ for p in var.prefixes : trim(p, "/")
+ if trim(p, "/") != ""
+ ])
+
+ # Values accepted by the s3:prefix condition.
+ #
+ # We allow:
+ # prefix
+ # prefix/
+ # prefix/*
+ #
+ # This is useful because S3 clients may list with different prefix forms.
+ list_prefixes = distinct(flatten([
+ for p in local.normalized_prefixes : [
+ p,
+ "${p}/",
+ "${p}/*"
+ ]
+ ]))
+
+ # Object-level resources.
+ #
+ # Allow both:
+ # arn:aws:s3:::container/prefix
+ # arn:aws:s3:::container/prefix/*
+ #
+ # The first one is not always required, but it makes the policy more robust
+ # if a client ever writes an object exactly named after the prefix.
+ object_resources = distinct(flatten([
+ for p in local.normalized_prefixes : [
+ "arn:aws:s3:::${var.container_name}/${p}",
+ "arn:aws:s3:::${var.container_name}/${p}/*"
+ ]
+ ]))
+
+ policy = jsonencode({
+ Version = "2012-10-17"
+
+ Statement = [
+ {
+ Sid = "ListOwnPrefixOnly"
+ Effect = "Allow"
+
+ Action = [
+ "s3:ListBucket",
+ "s3:GetBucketLocation",
+ "s3:ListBucketMultipartUploads"
+ ]
+
+ Resource = [
+ "arn:aws:s3:::${var.container_name}"
+ ]
+
+ Condition = {
+ StringLike = {
+ "s3:prefix" = local.list_prefixes
+ }
+ }
+ },
+
+ {
+ Sid = "ReadWriteOwnPrefixOnly"
+ Effect = "Allow"
+
+ Action = [
+ "s3:GetObject",
+ "s3:PutObject",
+ "s3:DeleteObject",
+ "s3:AbortMultipartUpload",
+ "s3:ListMultipartUploadParts"
+ ]
+
+ Resource = local.object_resources
+ }
+ ]
+ })
+}
+
+resource "ovh_cloud_project_user_s3_policy" "policy" {
+ service_name = var.service_name
+ user_id = ovh_cloud_project_user.user.id
+
+ policy = local.policy
+}
diff --git a/terraform/ovh-ops-backups/modules/object_storage_project_user/outputs.tf b/terraform/ovh-ops-backups/modules/object_storage_project_user/outputs.tf
new file mode 100644
--- /dev/null
+++ b/terraform/ovh-ops-backups/modules/object_storage_project_user/outputs.tf
@@ -0,0 +1,56 @@
+# -------------------------------------------------------------
+# Terraform :: OVH :: Public cloud :: ops-backups :: Project user
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: BSD-2-Clause
+# Description: Create user with access to object storage container
+# for backups in specified prefix.
+# Provider: OVH
+# -------------------------------------------------------------
+
+# -------------------------------------------------------------
+# Variables to describe the user in other systems (e.g. Vault)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+output "account_name" {
+ description = "Logical account name."
+ value = var.account_name
+}
+
+output "container_name" {
+ description = "S3 container name."
+ value = var.container_name
+}
+
+output "prefixes" {
+ description = "Allowed S3 prefixes."
+ value = local.normalized_prefixes
+}
+
+# -------------------------------------------------------------
+# Variables for the module resources
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+output "user" {
+ description = "OVH user"
+ value = {
+ id = ovh_cloud_project_user.user.id
+ openstack_rc = ovh_cloud_project_user.user.openstack_rc
+ username = ovh_cloud_project_user.user.username
+ }
+}
+
+output "user_password" {
+ description = "OVH user password"
+ sensitive = true
+ value = ovh_cloud_project_user.user.password
+}
+
+output "s3_credentials" {
+ description = "S3 credentials"
+ sensitive = true
+ value = {
+ access_key = ovh_cloud_project_user_s3_credential.s3_credentials.access_key_id
+ secret_key = ovh_cloud_project_user_s3_credential.s3_credentials.secret_access_key
+ }
+}
diff --git a/terraform/ovh-ops-backups/modules/object_storage_project_user/providers.tf b/terraform/ovh-ops-backups/modules/object_storage_project_user/providers.tf
new file mode 100644
--- /dev/null
+++ b/terraform/ovh-ops-backups/modules/object_storage_project_user/providers.tf
@@ -0,0 +1,23 @@
+# -------------------------------------------------------------
+# Terraform :: OVH :: Public cloud :: ops-backups :: Project user
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: BSD-2-Clause
+# Description: Create user with access to object storage container
+# for backups in specified prefix.
+# Provider: OVH
+# -------------------------------------------------------------
+
+terraform {
+ // Per `for` expression
+ required_version = ">= 0.12.0"
+
+ required_providers {
+ ovh = {
+ source = "ovh/ovh"
+
+ # For object lock support
+ version = ">= 2.11.0"
+ }
+ }
+}
diff --git a/terraform/ovh-ops-backups/modules/object_storage_project_user/variables.tf b/terraform/ovh-ops-backups/modules/object_storage_project_user/variables.tf
new file mode 100644
--- /dev/null
+++ b/terraform/ovh-ops-backups/modules/object_storage_project_user/variables.tf
@@ -0,0 +1,39 @@
+# -------------------------------------------------------------
+# Terraform :: OVH :: Public cloud :: ops-backups :: Project user
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: BSD-2-Clause
+# Description: Create user with access to object storage container
+# for backups in specified prefix.
+# Provider: OVH
+# -------------------------------------------------------------
+
+variable "service_name" {
+ description = "OVH Cloud Project service name."
+ type = string
+}
+
+variable "account_name" {
+ description = "Logical account name, for example user-bak-amaris-windriver."
+ type = string
+}
+
+variable "description" {
+ description = "Description of the OVH user."
+ type = string
+}
+
+variable "container_name" {
+ description = "Object storage container (S3 bucket) name."
+ type = string
+}
+
+variable "prefixes" {
+ description = "S3 key prefixes this account may access."
+ type = list(string)
+
+ validation {
+ condition = length(var.prefixes) > 0
+ error_message = "At least one S3 prefix is required."
+ }
+}
diff --git a/terraform/ovh-ops-backups/object_storage.tf b/terraform/ovh-ops-backups/object_storage.tf
--- a/terraform/ovh-ops-backups/object_storage.tf
+++ b/terraform/ovh-ops-backups/object_storage.tf
@@ -8,40 +8,6 @@
# Target: OVH Public Cloud > Nasqueron :: Operations :: Backups
# -------------------------------------------------------------
-locals {
- default_tags = {
- group = "operations"
- role = "backup"
- encryption = "client-side"
- privacy_level = "sensible"
- }
-
- backup_containers = {
- amaris = {
- container_name = "nasqueron-backups-amaris"
- purpose = "Main backup container"
-
- tags = local.default_tags
- }
-
- darak = {
- container_name = "nasqueron-backups-darak"
- purpose = "Dereckson backups"
-
- tags = merge(local.default_tags, {
- group = "user-dereckson"
- })
- }
-
- vakor = {
- container_name = "nasqueron-backups-vakor"
- purpose = "Vault backups"
-
- tags = local.default_tags
- }
- }
-}
-
module "backup" {
source = "./modules/object_storage_container"
for_each = local.backup_containers
diff --git a/terraform/ovh-ops-backups/users.tf b/terraform/ovh-ops-backups/users.tf
new file mode 100644
--- /dev/null
+++ b/terraform/ovh-ops-backups/users.tf
@@ -0,0 +1,52 @@
+# -------------------------------------------------------------
+# Terraform :: OVH :: S3 Users and Policies
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: BSD-2-Clause
+# Provider: OVH + Vault / OpenBao
+# Target: OVH Public Cloud > Nasqueron :: Operations :: Backups
+# complector.nasqueron.drake
+# -------------------------------------------------------------
+
+# -------------------------------------------------------------
+# Flattened backup containers and clients into client accounts
+#
+# Allow to create S3 users like user-bak-<container>-<client>
+# e.g. "user-bak-amaris-windriver"
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+locals {
+ backup_client_accounts = {
+ for account in flatten([
+ for container_key, container in local.backup_containers : [
+ for client_key, client in container.clients : {
+ key = "${container_key}-${client_key}"
+
+ container_key = container_key
+ container_name = container.container_name
+
+ client_key = client_key
+ prefixes = client.prefixes
+
+ account_name = "user-bak-${container_key}-${client_key}"
+ description = "Service account for ${client_key} on ${container.container_name}"
+ }
+ ]
+ ]) : account.key => account
+ }
+}
+
+# -------------------------------------------------------------
+# Create user accounts and apply prefixes policies
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+module "backup_client_accounts" {
+ source = "./modules/object_storage_project_user"
+ for_each = local.backup_client_accounts
+
+ service_name = ovh_cloud_project.nasqueron-ops-backups.id
+ account_name = each.value.account_name
+ description = each.value.description
+ container_name = each.value.container_name
+ prefixes = each.value.prefixes
+}
diff --git a/terraform/ovh-ops-backups/variables.tf b/terraform/ovh-ops-backups/variables.tf
deleted file mode 100644
--- a/terraform/ovh-ops-backups/variables.tf
+++ /dev/null
@@ -1,13 +0,0 @@
-# -------------------------------------------------------------
-# Terraform :: OVH :: Variables
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# Project: Nasqueron
-# License: BSD-2-Clause
-# Provider: OVH / Vault
-# -------------------------------------------------------------
-
-variable "bucket" {
- description = "The name of the bucket."
- type = string
- default = "nasqueron-backups-amaris"
-}
diff --git a/terraform/ovh-ops-backups/vault.tf b/terraform/ovh-ops-backups/vault.tf
new file mode 100644
--- /dev/null
+++ b/terraform/ovh-ops-backups/vault.tf
@@ -0,0 +1,44 @@
+# -------------------------------------------------------------
+# Terraform :: OVH :: Store S3 Credentials in OpenBao/Vault
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Nasqueron
+# License: BSD-2-Clause
+# Provider: OVH / Vault / OpenBao
+# Target: complector.nasqueron.drake
+# -------------------------------------------------------------
+
+locals {
+ s3_endpoint = "https://s3.eu-west-par.io.cloud.ovh.net"
+}
+
+resource "vault_kv_secret_v2" "ovh_s3_credentials" {
+ for_each = local.backup_client_accounts
+
+ mount = "ops"
+ name = "secrets/backups/ovh/s3/${each.key}"
+
+ data_json = jsonencode({
+ access_key = module.backup_client_accounts[each.key].s3_credentials.access_key
+ secret_key = module.backup_client_accounts[each.key].s3_credentials.secret_key
+ })
+
+ custom_metadata {
+ data = {
+ container_name = each.value.container_name
+ endpoint = "s3:${local.s3_endpoint}/${each.value.container_name}/"
+ prefixes = join(", ", each.value.prefixes)
+ }
+ }
+
+ # We use lifecycle to prevent Terraform from trying to update the secret
+ # if it is manually rotated or changed in Vault after initial creation.
+ # Note: The generated secret_access_key from OVH will still be present in
+ # the Terraform state file of the `ovh_cloud_project_user_s3_credential`
+ # resource, as Terraform must store managed resource attributes in state.
+ # Ensure your Terraform state backend is strictly encrypted and access-controlled.
+ lifecycle {
+ ignore_changes = [
+ data_json,
+ ]
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Mon, Sep 7, 02:05 (22 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4067792
Default Alt Text
D4206.diff (16 KB)

Event Timeline