diff --git a/modules/mpc-backup-key/README.md b/modules/mpc-backup-key/README.md new file mode 100644 index 0000000..8077dca --- /dev/null +++ b/modules/mpc-backup-key/README.md @@ -0,0 +1,44 @@ + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.10 | +| [aws](#requirement\_aws) | >= 6.0 | +| [random](#requirement\_random) | >= 3.1 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 6.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_kms_alias.this_backup](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource | +| [aws_kms_key.this_backup](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [mpc\_party\_cross\_account\_iam\_role\_arn](#input\_mpc\_party\_cross\_account\_iam\_role\_arn) | ARN of cross-account IAM role allowed for usage of KMS key | `string` | `null` | no | +| [mpc\_party\_kms\_alias](#input\_mpc\_party\_kms\_alias) | Alias for the KMS key | `string` | `null` | no | +| [mpc\_party\_kms\_backup\_description](#input\_mpc\_party\_kms\_backup\_description) | Description of KMS Key | `string` | `"Asymmetric KMS key backup for MPC Party"` | no | +| [mpc\_party\_kms\_backup\_vault\_customer\_master\_key\_spec](#input\_mpc\_party\_kms\_backup\_vault\_customer\_master\_key\_spec) | Key spec for the backup vault | `string` | `"ASYMMETRIC_DEFAULT"` | no | +| [mpc\_party\_kms\_backup\_vault\_key\_usage](#input\_mpc\_party\_kms\_backup\_vault\_key\_usage) | Key usage for the backup vault | `string` | `"ENCRYPT_DECRYPT"` | no | +| [mpc\_party\_kms\_deletion\_window\_in\_days](#input\_mpc\_party\_kms\_deletion\_window\_in\_days) | Deletion window in days for KMS key | `number` | `30` | no | +| [mpc\_party\_kms\_image\_attestation\_sha](#input\_mpc\_party\_kms\_image\_attestation\_sha) | Attestation SHA for KMS image | `string` | `null` | no | +| [tags](#input\_tags) | A map of tags to assign to the resource | `map(string)` |
{
"module": "mpc-party-backup",
"terraform": "true"
}
| no | + +## Outputs + +No outputs. + diff --git a/modules/mpc-backup-key/main.tf b/modules/mpc-backup-key/main.tf new file mode 100644 index 0000000..ce2f09e --- /dev/null +++ b/modules/mpc-backup-key/main.tf @@ -0,0 +1,77 @@ +# ************ +# Data Sources +# ************ +data "aws_caller_identity" "current" {} + +# ************ +# ASYMMETRIC KMS Key Backup for MPC Party +# ************ +resource "aws_kms_key" "this_backup" { + description = var.mpc_party_kms_backup_description + key_usage = var.mpc_party_kms_backup_vault_key_usage + customer_master_key_spec = var.mpc_party_kms_backup_vault_customer_master_key_spec + enable_key_rotation = false + deletion_window_in_days = var.mpc_party_kms_deletion_window_in_days + tags = var.tags + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "Allow access for Key Administrators", # https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-administrators + Effect = "Allow", + Principal = { + AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + }, + Action = [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:TagResource", + "kms:UntagResource", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ], + Resource = "*" + }, + { + Effect = "Allow", + Principal = { + AWS = var.mpc_party_cross_account_iam_role_arn + }, + Action = [ + "kms:GetPublicKey", + ], + Resource = "*" + }, + { + Effect = "Allow", + Principal = { + AWS = var.mpc_party_cross_account_iam_role_arn + }, + Action = [ + "kms:Decrypt", + "kms:GenerateDataKey", + ], + Resource = "*", + Condition = { + StringEqualsIgnoreCase = { + "kms:RecipientAttestation:ImageSha384" : var.mpc_party_kms_image_attestation_sha + } + } + }, + ] + }) +} + +resource "aws_kms_alias" "this_backup" { + name = "${var.mpc_party_kms_alias}-backup" + target_key_id = aws_kms_key.this_backup.key_id +} diff --git a/modules/mpc-backup-key/outputs.tf b/modules/mpc-backup-key/outputs.tf new file mode 100644 index 0000000..e69de29 diff --git a/modules/mpc-backup-key/variables.tf b/modules/mpc-backup-key/variables.tf new file mode 100644 index 0000000..f4cac4b --- /dev/null +++ b/modules/mpc-backup-key/variables.tf @@ -0,0 +1,58 @@ +# ************ +# General variables +# ************ +# Tagging +variable "tags" { + type = map(string) + description = "A map of tags to assign to the resource" + default = { + "terraform" = "true" + "module" = "mpc-party-backup" + } +} + +# ************ +# Variables for usage in main.tf +# ************ + +variable "mpc_party_cross_account_iam_role_arn" { + type = string + description = "ARN of cross-account IAM role allowed for usage of KMS key" + default = null +} + +variable "mpc_party_kms_image_attestation_sha" { + type = string + description = "Attestation SHA for KMS image" + default = null +} + +variable "mpc_party_kms_alias" { + type = string + description = "Alias for the KMS key" + default = null +} + +variable "mpc_party_kms_deletion_window_in_days" { + type = number + description = "Deletion window in days for KMS key" + default = 30 +} + +variable "mpc_party_kms_backup_description" { + type = string + description = "Description of KMS Key" + default = "Asymmetric KMS key backup for MPC Party" +} + +variable "mpc_party_kms_backup_vault_key_usage" { + type = string + description = "Key usage for the backup vault" + default = "ENCRYPT_DECRYPT" +} + +variable "mpc_party_kms_backup_vault_customer_master_key_spec" { + type = string + description = "Key spec for the backup vault" + default = "ASYMMETRIC_DEFAULT" +} diff --git a/modules/mpc-backup-key/versions.tf b/modules/mpc-backup-key/versions.tf new file mode 100644 index 0000000..03df166 --- /dev/null +++ b/modules/mpc-backup-key/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.10" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 6.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.1" + } + } +} diff --git a/modules/mpc-backup-vault/README.md b/modules/mpc-backup-vault/README.md new file mode 100644 index 0000000..fe9b1fc --- /dev/null +++ b/modules/mpc-backup-vault/README.md @@ -0,0 +1,61 @@ +# MPC Key backup modules\ + +This module is aim to create : +- bucket for backup vault + +The kms keys is handled by kms-stack terraform module in infra repo. + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.10 | +| [aws](#requirement\_aws) | >= 6.0 | +| [random](#requirement\_random) | >= 3.1 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 6.0 | +| [random](#provider\_random) | >= 3.1 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_iam_policy.mpc_aws](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.mpc_backup_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.mpc_backup_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_s3_bucket.backup_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket_ownership_controls.backup_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource | +| [aws_s3_bucket_policy.backup_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource | +| [aws_s3_bucket_public_access_block.backup_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | +| [aws_s3_bucket_versioning.backup_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource | +| [random_id.mpc_party_suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource | +| [aws_iam_policy_document.assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [bucket\_cross\_account\_id](#input\_bucket\_cross\_account\_id) | ID of the AWS account that can access the backup bucket. | `string` | n/a | yes | +| [bucket\_prefix](#input\_bucket\_prefix) | The prefix for the S3 bucket names | `string` | `"mpc-backup-vault"` | no | +| [party\_name](#input\_party\_name) | The name of the MPC party (used for resource naming and tagging) | `string` | n/a | yes | +| [tags](#input\_tags) | A map of tags to assign to the resource | `map(string)` |
{
"module": "mpc-party",
"terraform": "true"
}
| no | +| [trusted\_principal\_arns](#input\_trusted\_principal\_arns) | List of ARNs (users, roles, or root accounts) that can assume the backup role. | `list(string)` | `[]` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [bucket\_arn](#output\_bucket\_arn) | The ARN of the created S3 bucket | +| [bucket\_name](#output\_bucket\_name) | The name of the created S3 bucket | +| [role\_arn](#output\_role\_arn) | The ARN of the IAM role created for accessing the bucket | +| [role\_name](#output\_role\_name) | The name of the IAM role created for accessing the bucket | + diff --git a/modules/mpc-backup-vault/main.tf b/modules/mpc-backup-vault/main.tf new file mode 100644 index 0000000..c30469c --- /dev/null +++ b/modules/mpc-backup-vault/main.tf @@ -0,0 +1,120 @@ +# *************************************** +# Local variables +# *************************************** +resource "random_id" "mpc_party_suffix" { + byte_length = 4 +} +locals { + backup_bucket_name = "${var.bucket_prefix}-${var.party_name}-${random_id.mpc_party_suffix.hex}" +} + +# *************************************** +# S3 Buckets for Vault Private Storage +# *************************************** +resource "aws_s3_bucket" "backup_bucket" { + force_destroy = true + bucket = local.backup_bucket_name + tags = merge(var.tags, { + "Name" = local.backup_bucket_name + "Type" = "backup-vault" + "Party" = var.party_name + "Purpose" = "mpc-backup-storage" + }) +} + +resource "aws_s3_bucket_ownership_controls" "backup_bucket" { + bucket = aws_s3_bucket.backup_bucket.id + rule { + object_ownership = "BucketOwnerEnforced" + } +} + +resource "aws_s3_bucket_versioning" "backup_bucket" { + bucket = aws_s3_bucket.backup_bucket.id + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_public_access_block" "backup_bucket" { + bucket = aws_s3_bucket.backup_bucket.id + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_policy" "backup_bucket" { + bucket = aws_s3_bucket.backup_bucket.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "AllowCrossAccountBackup" + Effect = "Allow" + Principal = { + AWS = "arn:aws:iam::${var.bucket_cross_account_id}:root" + } + Action = "s3:*" + Resource = [ + "arn:aws:s3:::${aws_s3_bucket.backup_bucket.id}", + "arn:aws:s3:::${aws_s3_bucket.backup_bucket.id}/*" + ] + } + ] + }) +} + +# *************************************** +# IAM Role & Policy for MPC Backup Vault +# *************************************** + +# Trust policy: Allow trusted principals to assume this role +data "aws_iam_policy_document" "assume_role" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "AWS" + identifiers = var.trusted_principal_arns + } + } +} + +resource "aws_iam_role" "mpc_backup_role" { + name = "mpc-backup-${var.party_name}" + assume_role_policy = data.aws_iam_policy_document.assume_role.json + tags = var.tags +} + +# Policy allowing access to the bucket +resource "aws_iam_policy" "mpc_aws" { + name = "mpc-backup-${var.party_name}" + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "AllowObjectActions" + Effect = "Allow" + Action = "s3:*Object" + Resource = [ + "arn:aws:s3:::${aws_s3_bucket.backup_bucket.id}/*" + ] + }, + { + Sid = "AllowListBucket" + Effect = "Allow" + Action = "s3:ListBucket" + Resource = [ + "arn:aws:s3:::${aws_s3_bucket.backup_bucket.id}" + ] + } + ] + }) +} + +# Attach policy to the role +resource "aws_iam_role_policy_attachment" "mpc_backup_attach" { + role = aws_iam_role.mpc_backup_role.name + policy_arn = aws_iam_policy.mpc_aws.arn +} diff --git a/modules/mpc-backup-vault/outputs.tf b/modules/mpc-backup-vault/outputs.tf new file mode 100644 index 0000000..fd097be --- /dev/null +++ b/modules/mpc-backup-vault/outputs.tf @@ -0,0 +1,19 @@ +output "bucket_name" { + description = "The name of the created S3 bucket" + value = aws_s3_bucket.backup_bucket.id +} + +output "bucket_arn" { + description = "The ARN of the created S3 bucket" + value = aws_s3_bucket.backup_bucket.arn +} + +output "role_name" { + description = "The name of the IAM role created for accessing the bucket" + value = aws_iam_role.mpc_backup_role.name +} + +output "role_arn" { + description = "The ARN of the IAM role created for accessing the bucket" + value = aws_iam_role.mpc_backup_role.arn +} diff --git a/modules/mpc-backup-vault/variables.tf b/modules/mpc-backup-vault/variables.tf new file mode 100644 index 0000000..7d1a6f5 --- /dev/null +++ b/modules/mpc-backup-vault/variables.tf @@ -0,0 +1,37 @@ +# Tagging +variable "tags" { + type = map(string) + description = "A map of tags to assign to the resource" + default = { + "terraform" = "true" + "module" = "mpc-party" + } +} + +variable "bucket_prefix" { + type = string + description = "The prefix for the S3 bucket names" + default = "mpc-backup-vault" +} + +# MPC Party Configuration +variable "party_name" { + type = string + description = "The name of the MPC party (used for resource naming and tagging)" + + validation { + condition = can(regex("^[a-z0-9-]+$", var.party_name)) + error_message = "Party name must contain only lowercase letters, numbers, and hyphens." + } +} + +variable "trusted_principal_arns" { + type = list(string) + description = "List of ARNs (users, roles, or root accounts) that can assume the backup role." + default = [] +} + +variable "bucket_cross_account_id" { + type = string + description = "ID of the AWS account that can access the backup bucket." +} diff --git a/modules/mpc-backup-vault/versions.tf b/modules/mpc-backup-vault/versions.tf new file mode 100644 index 0000000..03df166 --- /dev/null +++ b/modules/mpc-backup-vault/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.10" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 6.0" + } + random = { + source = "hashicorp/random" + version = ">= 3.1" + } + } +} diff --git a/modules/mpc-party/README.md b/modules/mpc-party/README.md index df44639..f2b91ca 100644 --- a/modules/mpc-party/README.md +++ b/modules/mpc-party/README.md @@ -377,8 +377,10 @@ The module can optionally create: | [k8s\_namespace](#input\_k8s\_namespace) | The Kubernetes namespace for MPC party resources | `string` | `"kms-decentralized"` | no | | [k8s\_service\_account\_name](#input\_k8s\_service\_account\_name) | The name of the Kubernetes service account for MPC party | `string` | n/a | yes | | [kms\_backup\_external\_role\_arn](#input\_kms\_backup\_external\_role\_arn) | ARN of the backup vault for the KMS key | `string` | `null` | no | +| [kms\_backup\_vault\_bucket\_name](#input\_kms\_backup\_vault\_bucket\_name) | Backup vault S3 bucket name | `string` | `null` | no | | [kms\_backup\_vault\_customer\_master\_key\_spec](#input\_kms\_backup\_vault\_customer\_master\_key\_spec) | Key spec for the backup vault | `string` | `"ASYMMETRIC_DEFAULT"` | no | | [kms\_backup\_vault\_key\_usage](#input\_kms\_backup\_vault\_key\_usage) | Key usage for the backup vault | `string` | `"ENCRYPT_DECRYPT"` | no | +| [kms\_backup\_vault\_kms\_key\_arn](#input\_kms\_backup\_vault\_kms\_key\_arn) | KMS key ARN for the backup vault | `string` | `null` | no | | [kms\_connector\_enable\_txsender\_key](#input\_kms\_connector\_enable\_txsender\_key) | Whether to enable the KMS key for the kms-connector txsender | `bool` | `false` | no | | [kms\_connector\_txsender\_key\_spec](#input\_kms\_connector\_txsender\_key\_spec) | Specification for the KMS-Connector txsender (e.g., ECC\_SECG\_P256K1 for Ethereum key signing) | `string` | `"ECC_SECG_P256K1"` | no | | [kms\_connector\_txsender\_key\_usage](#input\_kms\_connector\_txsender\_key\_usage) | Key usage for KMS-Connector txsender | `string` | `"SIGN_VERIFY"` | no | diff --git a/modules/mpc-party/main.tf b/modules/mpc-party/main.tf index 25d4717..a4d124d 100644 --- a/modules/mpc-party/main.tf +++ b/modules/mpc-party/main.tf @@ -189,26 +189,46 @@ resource "aws_iam_policy" "mpc_aws" { name = "mpc-${var.cluster_name}-${var.party_name}" policy = jsonencode({ Version = "2012-10-17" - Statement = [ - { - Sid = "AllowObjectActions" - Effect = "Allow" - Action = "s3:*Object" - Resource = [ - "arn:aws:s3:::${aws_s3_bucket.vault_private_bucket.id}/*", - "arn:aws:s3:::${aws_s3_bucket.vault_public_bucket.id}/*", - ] - }, - { - Sid = "AllowListBucket" - Effect = "Allow" - Action = "s3:ListBucket" - Resource = [ - "arn:aws:s3:::${aws_s3_bucket.vault_private_bucket.id}", - "arn:aws:s3:::${aws_s3_bucket.vault_public_bucket.id}", - ] - } - ] + Statement = concat( + [ + { + Sid = "AllowObjectActions" + Effect = "Allow" + Action = "s3:*Object" + Resource = concat( + [ + "arn:aws:s3:::${aws_s3_bucket.vault_private_bucket.id}/*", + "arn:aws:s3:::${aws_s3_bucket.vault_public_bucket.id}/*", + ], + var.kms_enable_backup_vault && var.kms_backup_vault_bucket_name != null ? [ + "arn:aws:s3:::${var.kms_backup_vault_bucket_name}/*" + ] : [] + ) + }, + { + Sid = "AllowListBucket" + Effect = "Allow" + Action = "s3:ListBucket" + Resource = concat( + [ + "arn:aws:s3:::${aws_s3_bucket.vault_private_bucket.id}", + "arn:aws:s3:::${aws_s3_bucket.vault_public_bucket.id}", + ], + var.kms_enable_backup_vault && var.kms_backup_vault_bucket_name != null ? [ + "arn:aws:s3:::${var.kms_backup_vault_bucket_name}" + ] : [] + ) + } + ], + var.kms_enable_backup_vault && var.kms_backup_vault_kms_key_arn != null ? [ + { + Sid = "AllowCrossAccountKeyBackup" + Effect = "Allow" + Action = "kms:GetPublicKey" + Resource = var.kms_backup_vault_kms_key_arn + } + ] : [] + ) }) } diff --git a/modules/mpc-party/variables.tf b/modules/mpc-party/variables.tf index 339cd1f..2e012d8 100644 --- a/modules/mpc-party/variables.tf +++ b/modules/mpc-party/variables.tf @@ -402,18 +402,37 @@ variable "kms_connector_txsender_key_spec" { default = "ECC_SECG_P256K1" } +#****************************************************** +# Backup Vault Configuration +#****************************************************** variable "kms_enable_backup_vault" { type = bool description = "Whether to enable the backup vault for the KMS key" default = false } +variable "kms_backup_vault_bucket_name" { + type = string + description = "Backup vault S3 bucket name" + default = null +} + +variable "kms_backup_vault_kms_key_arn" { + type = string + description = "KMS key ARN for the backup vault" + default = null +} + +#****************************************************** +# We use : +# - mpc-backup-key terraform module to create the kms backup key +# - mpc-backup-vault terraform module to create the kms backup bucket +#****************************************************** variable "kms_backup_external_role_arn" { type = string description = "ARN of the backup vault for the KMS key" default = null } - variable "kms_backup_vault_key_usage" { type = string description = "Key usage for the backup vault" @@ -425,6 +444,7 @@ variable "kms_backup_vault_customer_master_key_spec" { description = "Key spec for the backup vault" default = "ASYMMETRIC_DEFAULT" } +#****************************************************** variable "nodegroup_enable_ssm_managed_instance" { type = bool