diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 7de1b52..2bc772c 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -9,7 +9,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.ref }} - - name: Render terraform docs inside the README.md and push changes back to PR branch + - name: Generate README.md for each Terraform nested module and push changes back to PR branch uses: terraform-docs/gh-actions@v1.3.0 with: working-dir: . @@ -17,4 +17,14 @@ jobs: recursive-path: modules output-file: README.md output-method: inject + git-push: "true" + + - name: Generate README.md for each example and push changes back to PR branch + uses: terraform-docs/gh-actions@v1.3.0 + with: + working-dir: . + recursive: true + recursive-path: examples + output-file: README.md + output-method: inject git-push: "true" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5606f4c..d6bfdbe 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ # .tfstate files *.tfstate -*.tfstate.* \ No newline at end of file +*.tfstate.* + +.idea \ No newline at end of file diff --git a/README.md b/README.md index 4bb3521..f43515c 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,16 @@ -# Illumio Terraform Submodules -Terraform submodules that add functionality to Illumios terraform provider. See the modules directory for the various sub modules usage. - - -## Availible Features -1. Onboarding and deploying a cloud-opeartor and credentials to a k8s cluster - -## Usage - -``` -provider "helm" { - kubernetes { - config_path = "~/.kube/config" # Adjust this path as needed - } -} - -provider "illumio-cloudsecure" { - client_id = var.illumio_cloudsecure_client_id - client_secret = var.illumio_cloudsecure_client_secret -} - -module "k8s_cluster" { - source = "github.com/illumio/terraform-illumio-cloudsecure//modules/k8s_cluster?ref=v0.0.3" - illumio_region = var.illumio_region - name = var.name - description = var.description -} -``` +# Illumio CloudSecure Terraform Modules +Terraform submodules that add functionality to Illumio's CloudSecure Terraform provider. See the modules directory for the various submodules' usage. + +## Available Nested Modules +* `aws_account`: onboarding of an AWS account with CloudSecure. +* `k8s_cluster`: deployment and onboarding of CloudSecure's `cloud-operator` into a k8s cluster. ## Requirements | Name | Version | |------|---------| -| [illumio-cloudsecure](#requirement\_illumio-cloudsecure) | ~> 1.0.9 | +| [illumio-cloudsecure](#requirement\_illumio-cloudsecure) | ~> 1.0.11 | ## Providers diff --git a/examples/aws_account/README.md b/examples/aws_account/README.md new file mode 100644 index 0000000..70f3da7 --- /dev/null +++ b/examples/aws_account/README.md @@ -0,0 +1,33 @@ + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | ~>3.0 | +| [illumio-cloudsecure](#requirement\_illumio-cloudsecure) | ~> 1.0.11 | + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [aws\_account\_dev](#module\_aws\_account\_dev) | github.com/illumio/terraform-illumio-cloudsecure//modules/aws_account | v1.1.0 | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [illumio\_cloudsecure\_client\_id](#input\_illumio\_cloudsecure\_client\_id) | The OAuth 2 client identifier used to authenticate against the CloudSecure Config API. | `string` | n/a | yes | +| [illumio\_cloudsecure\_client\_secret](#input\_illumio\_cloudsecure\_client\_secret) | The OAuth 2 client secret used to authenticate against the CloudSecure Config API. | `string` | n/a | yes | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/examples/aws_account/main.tf b/examples/aws_account/main.tf new file mode 100644 index 0000000..9e1dba1 --- /dev/null +++ b/examples/aws_account/main.tf @@ -0,0 +1,17 @@ +provider "aws" { + region = "us-west-1" +} + +provider "illumio-cloudsecure" { + client_id = var.illumio_cloudsecure_client_id + client_secret = var.illumio_cloudsecure_client_secret +} + +module "aws_account_dev" { + source = "github.com/illumio/terraform-illumio-cloudsecure//modules/aws_account?ref=v1.1.0" + name = "Test Account" + tags = { + Name = "CloudSecure Account Policy" + Owner = "Engineering" + } +} \ No newline at end of file diff --git a/examples/aws_account/outputs.tf b/examples/aws_account/outputs.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/aws_account/variables.tf b/examples/aws_account/variables.tf new file mode 100644 index 0000000..116db84 --- /dev/null +++ b/examples/aws_account/variables.tf @@ -0,0 +1,18 @@ +variable "illumio_cloudsecure_client_id" { + type = string + description = "The OAuth 2 client identifier used to authenticate against the CloudSecure Config API." + validation { + condition = length(var.name) > 1 + error_message = "The illumio_cloudsecure_client_id value must not be empty." + } +} + +variable "illumio_cloudsecure_client_secret" { + type = string + sensitive = true + description = "The OAuth 2 client secret used to authenticate against the CloudSecure Config API." + validation { + condition = length(var.name) > 1 + error_message = "The illumio_cloudsecure_client_secret value must not be empty." + } +} diff --git a/examples/aws_account/versions.tf b/examples/aws_account/versions.tf new file mode 100644 index 0000000..10aa908 --- /dev/null +++ b/examples/aws_account/versions.tf @@ -0,0 +1,12 @@ +terraform { + required_providers { + illumio-cloudsecure = { + source = "illumio/illumio-cloudsecure" + version = "~> 1.0.11" + } + aws = { + source = "hashicorp/aws" + version = "~>3.0" + } + } +} diff --git a/examples/k8s_cluster/README.md b/examples/k8s_cluster/README.md index af5d2e5..2ab0373 100644 --- a/examples/k8s_cluster/README.md +++ b/examples/k8s_cluster/README.md @@ -4,7 +4,7 @@ | Name | Version | |------|---------| | [helm](#requirement\_helm) | ~>2.15.0 | -| [illumio-cloudsecure](#requirement\_illumio-cloudsecure) | ~> 1.0.9 | +| [illumio-cloudsecure](#requirement\_illumio-cloudsecure) | ~> 1.0.11 | ## Providers @@ -14,7 +14,7 @@ No providers. | Name | Source | Version | |------|--------|---------| -| [k8s\_cluster](#module\_k8s\_cluster) | ../../modules/k8s_cluster | n/a | +| [k8s\_cluster\_dev](#module\_k8s\_cluster\_dev) | github.com/illumio/terraform-illumio-cloudsecure//modules/k8s_cluster | v1.1.0 | ## Resources @@ -24,16 +24,10 @@ No resources. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [description](#input\_description) | The description of the onboarding credential. | `string` | `"Credential to onboard dev clusters in aws-us-west-2 illumio region"` | no | | [illumio\_cloudsecure\_client\_id](#input\_illumio\_cloudsecure\_client\_id) | The OAuth 2 client identifier used to authenticate against the CloudSecure Config API. | `string` | n/a | yes | | [illumio\_cloudsecure\_client\_secret](#input\_illumio\_cloudsecure\_client\_secret) | The OAuth 2 client secret used to authenticate against the CloudSecure Config API. | `string` | n/a | yes | -| [illumio\_region](#input\_illumio\_region) | The Illumio region where the Kubernetes cluster is located. | `string` | `"aws-us-west-2"` | no | -| [name](#input\_name) | The name of the onboarding credential and Helm release. | `string` | `"example-release"` | no | ## Outputs -| Name | Description | -|------|-------------| -| [client\_id](#output\_client\_id) | The client\_id to use to onboard k8s clusters. | -| [client\_secret](#output\_client\_secret) | The client\_secret to use to onboard k8s clusters. | +No outputs. \ No newline at end of file diff --git a/examples/k8s_cluster/main.tf b/examples/k8s_cluster/main.tf index fb5261d..6615738 100644 --- a/examples/k8s_cluster/main.tf +++ b/examples/k8s_cluster/main.tf @@ -9,9 +9,9 @@ provider "illumio-cloudsecure" { client_secret = var.illumio_cloudsecure_client_secret } -module "k8s_cluster" { - source = "github.com/illumio/terraform-illumio-cloudsecure//modules/k8s_cluster?ref=v1.0.0" - illumio_region = var.illumio_region - name = var.name - description = var.description +module "k8s_cluster_dev" { + source = "github.com/illumio/terraform-illumio-cloudsecure//modules/k8s_cluster?ref=v1.1.0" + illumio_region = "aws-us-west-2" + name = "example-release" + description = "Dev cluster in aws-us-west-2" } \ No newline at end of file diff --git a/examples/k8s_cluster/output.tf b/examples/k8s_cluster/output.tf deleted file mode 100644 index b329262..0000000 --- a/examples/k8s_cluster/output.tf +++ /dev/null @@ -1,10 +0,0 @@ -output "client_id" { - value = module.k8s_cluster.client_id - description = "The client_id to use to onboard k8s clusters." -} - -output "client_secret" { - value = module.k8s_cluster.client_secret - description = "The client_secret to use to onboard k8s clusters." - sensitive = true -} \ No newline at end of file diff --git a/examples/k8s_cluster/outputs.tf b/examples/k8s_cluster/outputs.tf new file mode 100644 index 0000000..e69de29 diff --git a/examples/k8s_cluster/variables.tf b/examples/k8s_cluster/variables.tf index 181b194..491d841 100644 --- a/examples/k8s_cluster/variables.tf +++ b/examples/k8s_cluster/variables.tf @@ -1,21 +1,3 @@ -variable "illumio_region" { - description = "The Illumio region where the Kubernetes cluster is located." - type = string - default = "aws-us-west-2" -} - -variable "name" { - description = "The name of the onboarding credential and Helm release." - type = string - default = "example-release" -} - -variable "description" { - description = "The description of the onboarding credential." - type = string - default = "Credential to onboard dev clusters in aws-us-west-2 illumio region" -} - variable "illumio_cloudsecure_client_id" { type = string description = "The OAuth 2 client identifier used to authenticate against the CloudSecure Config API." diff --git a/examples/k8s_cluster/versions.tf b/examples/k8s_cluster/versions.tf index eac13bb..b086983 100644 --- a/examples/k8s_cluster/versions.tf +++ b/examples/k8s_cluster/versions.tf @@ -2,7 +2,7 @@ terraform { required_providers { illumio-cloudsecure = { source = "illumio/illumio-cloudsecure" - version = "~> 1.0.9" + version = "~> 1.0.11" } helm = { source = "hashicorp/helm" diff --git a/main.tf b/main.tf index ca42281..6a2a98f 100644 --- a/main.tf +++ b/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { illumio-cloudsecure = { source = "illumio/illumio-cloudsecure" - version = "~> 1.0.9" + version = "~> 1.0.11" } } } \ No newline at end of file diff --git a/modules/aws_account/README.md b/modules/aws_account/README.md new file mode 100644 index 0000000..e79cc4e --- /dev/null +++ b/modules/aws_account/README.md @@ -0,0 +1,50 @@ + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | ~> 3.0 | +| [illumio-cloudsecure](#requirement\_illumio-cloudsecure) | ~> 1.0.11 | +| [random](#requirement\_random) | ~> 3.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | ~> 3.0 | +| [illumio-cloudsecure](#provider\_illumio-cloudsecure) | ~> 1.0.11 | +| [random](#provider\_random) | ~> 3.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_iam_role.role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy.protection](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.read](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [illumio-cloudsecure_aws_account.account](https://registry.terraform.io/providers/illumio/illumio-cloudsecure/latest/docs/resources/aws_account) | resource | +| [random_uuid.role_secret](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/uuid) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_organizations_organization.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [iam\_name\_prefix](#input\_iam\_name\_prefix) | The prefix given to all AWS IAM resource names. | `string` | `"IllumioCloudIntegration"` | no | +| [illumio\_cloudsecure\_account\_id](#input\_illumio\_cloudsecure\_account\_id) | The CloudSecure AWS account ID that is given the IAM role. | `string` | `"712001342241"` | no | +| [mode](#input\_mode) | The account's access mode, must be "ReadWrite" (default) or "Read". | `string` | `"ReadWrite"` | no | +| [name](#input\_name) | The name of this account in CloudSecure. | `string` | n/a | yes | +| [tags](#input\_tags) | The optional tags added to every configured AWS resource. | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [role\_arn](#output\_role\_arn) | The ARN of the IAM role granted to the CloudSecure account. | + \ No newline at end of file diff --git a/modules/aws_account/main.tf b/modules/aws_account/main.tf new file mode 100644 index 0000000..1bbceb1 --- /dev/null +++ b/modules/aws_account/main.tf @@ -0,0 +1,188 @@ +terraform { + required_providers { + illumio-cloudsecure = { + source = "illumio/illumio-cloudsecure" + version = "~> 1.0.11" + } + aws = { + source = "hashicorp/aws" + version = "~> 3.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.0" + } + } +} + +data "aws_partition" "current" {} + +resource "random_uuid" "role_secret" {} + +resource "aws_iam_role_policy" "read" { + name = var.iam_name_prefix + "Policy" + tags = var.tags + role = aws_iam_role.role.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "apigateway:GET", + "autoscaling:Describe*", + "cloudtrail:DescribeTrails", + "cloudtrail:GetTrailStatus", + "cloudtrail:LookupEvents", + "cloudwatch:Describe*", + "cloudwatch:Get*", + "cloudwatch:List*", + "codedeploy:List*", + "codedeploy:BatchGet*", + "directconnect:Describe*", + "docdb-elastic:GetCluster", + "docdb-elastic:ListTagsForResource", + "dynamodb:List*", + "dynamodb:Describe*", + "ec2:Describe*", + "ec2:SearchTransitGatewayMulticastGroups", + "ecs:Describe*", + "ecs:List*", + "elasticache:Describe*", + "elasticache:List*", + "elasticfilesystem:DescribeAccessPoints", + "elasticfilesystem:DescribeFileSystems", + "elasticfilesystem:DescribeTags", + "elasticloadbalancing:Describe*", + "elasticmapreduce:List*", + "elasticmapreduce:Describe*", + "es:ListTags", + "es:ListDomainNames", + "es:DescribeElasticsearchDomains", + "fsx:DescribeFileSystems", + "fsx:ListTagsForResource", + "health:DescribeEvents", + "health:DescribeEventDetails", + "health:DescribeAffectedEntities", + "kinesis:List*", + "kinesis:Describe*", + "lambda:GetPolicy", + "lambda:List*", + "logs:TestMetricFilter", + "logs:DescribeSubscriptionFilters", + "organizations:Describe*", + "organizations:List*", + "rds:Describe*", + "rds:List*", + "redshift:DescribeClusters", + "redshift:DescribeLoggingStatus", + "route53:List*", + "s3:GetBucketLogging", + "s3:GetBucketLocation", + "s3:GetBucketNotification", + "s3:GetBucketTagging", + "s3:ListAllMyBuckets", + "sns:List*", + "sqs:ListQueues", + "states:ListStateMachines", + "states:DescribeStateMachine", + "support:DescribeTrustedAdvisor*", + "support:RefreshTrustedAdvisorCheck", + "tag:GetResources", + "tag:GetTagKeys", + "tag:GetTagValues", + "xray:BatchGetTraces", + "xray:GetTraceSummaries", + "networkmanager:ListCoreNetworks", + "networkmanager:GetCoreNetwork", + "networkmanager:ListAttachments", + "networkmanager:GetVpcAttachment", + "networkmanager:GetSiteToSiteVpnAttachment", + "networkmanager:GetConnectAttachment", + "networkmanager:GetTransitGatewayRouteTableAttachment", + "networkmanager:ListPeerings", + "networkmanager:GetTransitGatewayPeering", + "networkmanager:GetTransitGatewayRegistrations" + ], + Resource = "*" + } + ] + }) +} +resource "aws_iam_role_policy" "protection" { + count = var.mode == "ReadWrite" ? 1 : 0 + name = var.iam_name_prefix + "ProtectionPolicy" + tags = var.tags + role = aws_iam_role.role.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:RevokeSecurityGroupIngress", + "ec2:UpdateSecurityGroupRuleDescriptionsIngress", + "ec2:AuthorizeSecurityGroupEgress", + "ec2:RevokeSecurityGroupEgress", + "ec2:UpdateSecurityGroupRuleDescriptionsEgress", + "ec2:ModifySecurityGroupRules", + "ec2:DescribeTags", + "ec2:CreateTags", + "ec2:DeleteTags", + "ec2:DescribeNetworkAcls", + "ec2:CreateNetworkAclEntry", + "ec2:ReplaceNetworkAclEntry", + "ec2:DeleteNetworkAclEntry" + ], + Resource = [ + "arn:aws:ec2:*:*:security-group-rule/*", + "arn:aws:ec2:*:*:security-group/*", + "arn:aws:ec2:*:*:network-acl/*" + ] + } + ] + }) +} + +resource "aws_iam_role" "role" { + name = var.iam_name_prefix + "Role" + tags = var.tags + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${var.illumio_cloudsecure_account_id}:root" + } + Action = "sts:AssumeRole" + Condition = { + StringEquals = { + "sts:ExternalId" = random_uuid.role_secret.result + } + } + } + ] + }) + + managed_policy_arns = [ + "arn:aws:iam::aws:policy/SecurityAudit" + ] +} + +# Data source to get the AWS account ID. +data "aws_caller_identity" "current" {} + +# Data source to get the AWS org. +data "aws_organizations_organization" "current" {} + +// Onboards this AWS account with CloudSecure. +resource "illumio-cloudsecure_aws_account" "account" { + account_id = data.aws_caller_identity.current.account_id + mode = var.mode + name = var.name + organization_id = data.aws_organizations_organization.current.id + role_arn = aws_iam_role.role.arn + role_external_id = random_uuid.role_secret.result +} diff --git a/modules/aws_account/outputs.tf b/modules/aws_account/outputs.tf new file mode 100644 index 0000000..0fe42ad --- /dev/null +++ b/modules/aws_account/outputs.tf @@ -0,0 +1,4 @@ +output "role_arn" { + value = aws_iam_role.role.arn + description = "The ARN of the IAM role granted to the CloudSecure account." +} \ No newline at end of file diff --git a/modules/aws_account/variables.tf b/modules/aws_account/variables.tf new file mode 100644 index 0000000..88bba05 --- /dev/null +++ b/modules/aws_account/variables.tf @@ -0,0 +1,44 @@ +variable "iam_name_prefix" { + description = "The prefix given to all AWS IAM resource names." + type = string + default = "IllumioCloudIntegration" + validation { + condition = length(var.iam_name_prefix) > 1 + error_message = "The iam_name_prefix value must not be empty." + } +} + +variable "illumio_cloudsecure_account_id" { + description = "The CloudSecure AWS account ID that is given the IAM role." + type = string + default = "712001342241" + validation { + condition = length(var.illumio_cloudsecure_account_id) == 12 + error_message = "The illumio_cloudsecure_account_id value must be a 12-digit number." + } +} + +variable "mode" { + description = "The account's access mode, must be \"ReadWrite\" (default) or \"Read\"." + type = string + default = "ReadWrite" + validation { + condition = contains(["Read", "ReadWrite"], var.mode) + error_message = "The mode value must be \"ReadWrite\" or \"Read\"." + } +} + +variable "name" { + description = "The name of this account in CloudSecure." + type = string + validation { + condition = length(var.name) > 1 + error_message = "The name value must not be empty." + } +} + +variable "tags" { + description = "The optional tags added to every configured AWS resource." + type = map(string) + default = {} +} \ No newline at end of file diff --git a/modules/k8s_cluster/README.md b/modules/k8s_cluster/README.md index e182abe..293c55c 100644 --- a/modules/k8s_cluster/README.md +++ b/modules/k8s_cluster/README.md @@ -4,14 +4,14 @@ | Name | Version | |------|---------| | [helm](#requirement\_helm) | ~>2.15.0 | -| [illumio-cloudsecure](#requirement\_illumio-cloudsecure) | ~> 1.0.9 | +| [illumio-cloudsecure](#requirement\_illumio-cloudsecure) | ~> 1.0.11 | ## Providers | Name | Version | |------|---------| | [helm](#provider\_helm) | ~>2.15.0 | -| [illumio-cloudsecure](#provider\_illumio-cloudsecure) | ~> 1.0.9 | +| [illumio-cloudsecure](#provider\_illumio-cloudsecure) | ~> 1.0.11 | ## Modules @@ -41,4 +41,4 @@ No modules. |------|-------------| | [client\_id](#output\_client\_id) | The client\_id that was used to onboard the k8s cluster, and may be used to onboard other clusters. | | [client\_secret](#output\_client\_secret) | The client\_secret that was used to onboard the k8s cluster, and may be used to onboard other clusters. | - + \ No newline at end of file diff --git a/modules/k8s_cluster/output.tf b/modules/k8s_cluster/outputs.tf similarity index 100% rename from modules/k8s_cluster/output.tf rename to modules/k8s_cluster/outputs.tf diff --git a/modules/k8s_cluster/versions.tf b/modules/k8s_cluster/versions.tf index eac13bb..b086983 100644 --- a/modules/k8s_cluster/versions.tf +++ b/modules/k8s_cluster/versions.tf @@ -2,7 +2,7 @@ terraform { required_providers { illumio-cloudsecure = { source = "illumio/illumio-cloudsecure" - version = "~> 1.0.9" + version = "~> 1.0.11" } helm = { source = "hashicorp/helm"