From 7c96b026d1a4fa071ef8b45a2937eb3ee1cdd238 Mon Sep 17 00:00:00 2001 From: Wilson de Carvalho <796900+wcmjunior@users.noreply.github.com> Date: Sun, 11 Feb 2024 00:38:46 -0800 Subject: [PATCH 1/2] Add AWS RDS IAM auth guide --- docs/guides/iam_auth_rds_pg.md | 275 ++++++++++++++++++++++ docs/guides/s3_browser_and_aws_cli.md | 14 +- examples/guides/iam_auth_rds_pg.tf | 245 +++++++++++++++++++ examples/guides/s3_browser_and_aws_cli.tf | 14 +- templates/guides/iam_auth_rds_pg.md.tmpl | 29 +++ 5 files changed, 559 insertions(+), 18 deletions(-) create mode 100644 docs/guides/iam_auth_rds_pg.md create mode 100644 examples/guides/iam_auth_rds_pg.tf create mode 100644 templates/guides/iam_auth_rds_pg.md.tmpl diff --git a/docs/guides/iam_auth_rds_pg.md b/docs/guides/iam_auth_rds_pg.md new file mode 100644 index 00000000..f6aa6a5a --- /dev/null +++ b/docs/guides/iam_auth_rds_pg.md @@ -0,0 +1,275 @@ +--- +page_title: "Authentication from sidecar to RDS using an AWS IAM role" +--- + +-> **Note** This guide assumes you have an RDS PG instance that is +reachable from the subnets the sidecar will be deployed to. Make +sure you create the user in the database that corresponds to the role +created in this example and grant the `rds_iam` permission as shown +in the following command: + +``` +CREATE USER "arn:aws:iam:::role/my-sidecar_rds_access_role"; +GRANT rds_iam TO "arn:aws:iam:::role/my-sidecar_rds_access_role"; +``` + +Use this guide to create the minimum required configuration in both Cyral +Control Plane and your AWS account to deploy a Cyral Sidecar to AWS EC2 +to protect your RDS instance using an IAM role to allow the sidecar to +connect to your database. + +By running this example you will have a fully functional sidecar on your AWS +account. Read the comments and update the necessary parameters as instructed. + +See the [Cyral Sidecar module for AWS EC2](https://registry.terraform.io/modules/cyralinc/sidecar-ec2/aws/latest) +for more details on how the sidecar is deployed to AWS and more advanced configurations. + +See also the official AWS documentation on [IAM database authentication](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html). + +```terraform +terraform { + required_providers { + cyral = { + source = "cyralinc/cyral" + version = "~> 4.7" + } + } +} + +locals { + # Replace [TENANT] by your tenant name. Ex: mycompany.app.cyral.com + control_plane_host = "[TENANT].app.cyral.com" + + # Use the name of the IdP that will be used to access the RDS instance + idp = { + name = "" + } + + repos = { + pg = { + host = "" + port = 5432 + } + } + + sidecar = { + # Set to true if you want a sidecar deployed with an + # internet-facing load balancer (requires a public subnet). + public_sidecar = false + + # Set the AWS region that the sidecar will be deployed to + region = "" + # Set the ID of VPC that the sidecar will be deployed to + vpc_id = "" + # Set the IDs of the subnets that the sidecar will be deployed to + subnets = [""] + # Name of the CloudWatch log group used to push logs + cloudwatch_log_group_name = "cyral-example-loggroup" + + # Set the allowed CIDR block for SSH access to the sidecar + ssh_inbound_cidr = ["0.0.0.0/0"] + # Set the allowed CIDR block for database access through the + # sidecar + db_inbound_cidr = ["0.0.0.0/0"] + # Set the allowed CIDR block for monitoring requests to the + # sidecar + monitoring_inbound_cidr = ["0.0.0.0/0"] + + # Optionally set the hosted zone ID that will be used to create the + # DNS name in parameter `dns_name` + dns_hosted_zone_id = "" + # Optionally set the DNS name that will be used by your sidecar. Ex: + # sidecar.mycompany.com + dns_name = "" + } +} + +provider "aws" { + region = local.sidecar.region +} + +# Follow the instructions in the Cyral Terraform Provider page to set +# up the credentials: +# +# * https://registry.terraform.io/providers/cyralinc/cyral/latest/docs +provider "cyral" { + client_id = "" + client_secret = "" + + control_plane = local.control_plane_host +} + +# The log group is created in AWS by module.cyral_sidecar +# when the sidecar is deployed. +resource "cyral_integration_logging" "cloudwatch" { + name = "my-cloudwatch" + cloudwatch { + region = local.sidecar.region + group = local.sidecar.cloudwatch_log_group_name + stream = "cyral-sidecar" + } +} + +resource "cyral_sidecar" "sidecar" { + name = "my-sidecar" + deployment_method = "terraform" + activity_log_integration_id = cyral_integration_logging.cloudwatch.id +} + +resource "cyral_sidecar_credentials" "sidecar_credentials" { + sidecar_id = cyral_sidecar.sidecar.id +} + +resource "cyral_repository" "pg" { + name = "pgRepo" + type = "postgresql" + + repo_node { + host = local.repos.pg.host + port = local.repos.pg.port + } +} + +resource "cyral_sidecar_listener" "pg" { + sidecar_id = cyral_sidecar.sidecar.id + repo_types = ["postgresql"] + network_address { + port = local.repos.pg.port + } +} + +resource "cyral_repository_binding" "pg" { + sidecar_id = cyral_sidecar.sidecar.id + repository_id = cyral_repository.pg.id + listener_binding { + listener_id = cyral_sidecar_listener.pg.listener_id + } +} + +data "cyral_integration_idp_saml" "saml" { + display_name = local.idp.name +} + +# Let users from the provided `identity_provider` use SSO +# to access the database +resource "cyral_repository_conf_auth" "pg" { + repository_id = cyral_repository.pg.id + + client_tls = "enable" + repo_tls = "enable" + + identity_provider = data.cyral_integration_idp_saml.saml.idp_list[0].id +} + +# Enables the access portal for this repository in the +# especified sidecar +resource "cyral_repository_access_gateway" "pg" { + repository_id = cyral_repository.pg.id + sidecar_id = cyral_sidecar.sidecar.id + binding_id = cyral_repository_binding.pg.binding_id +} + +########################################################################### +# Creates an IAM policy that the sidecar will assume in order to access +# the RDS instance. In this example, the policy attached to the role will +# let the sidecar connect to all databases in all available accounts and +# regions. +# +# This should NOT be used in production. Refer to the AWS documentation +# for guidance on how to restrict to the database you plan to protect. +# +data "aws_iam_policy_document" "rds_access_policy" { + statement { + actions = ["rds-db:connect"] + resources = [ + "*" + ] + } +} + +resource "aws_iam_policy" "rds_access_policy" { + name = "my-sidecar_access_policy" + path = "/" + description = "Allow sidecar to connect to all RDS instances" + policy = data.aws_iam_policy_document.rds_access_policy.json +} + +data "aws_iam_policy_document" "sidecar_trust_policy" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "AWS" + identifiers = [module.cyral_sidecar.aws_iam_role_arn] + } + } +} + +resource "aws_iam_role" "rds_role" { + name = "my-sidecar_rds_access_role" + path = "/" + assume_role_policy = data.aws_iam_policy_document.sidecar_trust_policy.json +} + +resource "aws_iam_role_policy_attachment" "rds_role_policy_attachment" { + role = aws_iam_role.rds_role.name + policy_arn = aws_iam_policy.rds_access_policy.arn +} +########################################################################### + +resource "cyral_repository_user_account" "pg_repo_user_account" { + # You may opt for a better name here as this is the name that will + # be shown in the UI + name = "my-sidecar_rds_access_role" + repository_id = cyral_repository.pg.id + auth_scheme { + aws_iam { + role_arn = aws_iam_role.rds_role.arn + } + } +} + +# Set the proper identity for the username, email or group that will +# be allowed to access the PG database using SSO +resource "cyral_repository_access_rules" "access_rule" { + repository_id = cyral_repository.pg.id + user_account_id = cyral_repository_user_account.pg_repo_user_account.user_account_id + rule { + identity { + type = "email" + name = "myuser@mycompany.com" + } + } +} + +module "cyral_sidecar" { + source = "cyralinc/sidecar-ec2/aws" + + # Use the module version that is compatible with your sidecar. + version = "~> 4.3" + + sidecar_id = cyral_sidecar.sidecar.id + control_plane = local.control_plane_host + client_id = cyral_sidecar_credentials.sidecar_credentials.client_id + client_secret = cyral_sidecar_credentials.sidecar_credentials.client_secret + + sidecar_ports = [local.repos.pg.port] + + vpc_id = local.sidecar.vpc_id + subnets = local.sidecar.subnets + + ssh_inbound_cidr = local.sidecar.ssh_inbound_cidr + db_inbound_cidr = local.sidecar.db_inbound_cidr + monitoring_inbound_cidr = local.sidecar.monitoring_inbound_cidr + + load_balancer_scheme = local.sidecar.public_sidecar ? "internet-facing" : "internal" + associate_public_ip_address = local.sidecar.public_sidecar + + sidecar_dns_hosted_zone_id = local.sidecar.dns_hosted_zone_id + sidecar_dns_name = local.sidecar.dns_name +} + +output "sidecar_load_balancer_dns" { + value = module.cyral_sidecar.sidecar_load_balancer_dns +} +``` diff --git a/docs/guides/s3_browser_and_aws_cli.md b/docs/guides/s3_browser_and_aws_cli.md index 6f206043..4ab430ce 100644 --- a/docs/guides/s3_browser_and_aws_cli.md +++ b/docs/guides/s3_browser_and_aws_cli.md @@ -50,11 +50,6 @@ locals { # internet-facing load balancer (requires a public subnet). public_sidecar = true - # Set the desired sidecar version or leave it empty if - # you prefer to control the version from the control plane - # (later only possible in CPs >=v4.10). - sidecar_version = "v4.10.1" - # Set the AWS region that the sidecar will be deployed to region = "" # Set the ID of VPC that the sidecar will be deployed to @@ -165,7 +160,7 @@ resource "cyral_repository_binding" "s3" { } data "cyral_integration_idp_saml" "saml" { - display_name = local.idp.name + display_name = local.idp.name } # Let users from the provided `identity_provider` use SSO @@ -187,7 +182,10 @@ resource "cyral_repository_access_gateway" "s3" { # Creates an IAM policy that the sidecar will assume in order to access # your S3 bucket. In this example, the policy attached to the role will # let the sidecar access all buckets. - +# +# This should NOT be used in production. Refer to the AWS documentation +# for guidance on how to restrict to the buckets you plan to protect. +# data "aws_iam_policy_document" "s3_access_policy" { statement { actions = ["s3:*"] @@ -256,8 +254,6 @@ module "cyral_sidecar" { # Use the module version that is compatible with your sidecar. version = "~> 4.3" - sidecar_version = local.sidecar.sidecar_version - sidecar_id = cyral_sidecar.sidecar.id control_plane = local.control_plane_host client_id = cyral_sidecar_credentials.sidecar_credentials.client_id diff --git a/examples/guides/iam_auth_rds_pg.tf b/examples/guides/iam_auth_rds_pg.tf new file mode 100644 index 00000000..624f9fba --- /dev/null +++ b/examples/guides/iam_auth_rds_pg.tf @@ -0,0 +1,245 @@ +terraform { + required_providers { + cyral = { + source = "cyralinc/cyral" + version = "~> 4.7" + } + } +} + +locals { + # Replace [TENANT] by your tenant name. Ex: mycompany.app.cyral.com + control_plane_host = "[TENANT].app.cyral.com" + + # Use the name of the IdP that will be used to access the RDS instance + idp = { + name = "" + } + + repos = { + pg = { + host = "" + port = 5432 + } + } + + sidecar = { + # Set to true if you want a sidecar deployed with an + # internet-facing load balancer (requires a public subnet). + public_sidecar = false + + # Set the AWS region that the sidecar will be deployed to + region = "" + # Set the ID of VPC that the sidecar will be deployed to + vpc_id = "" + # Set the IDs of the subnets that the sidecar will be deployed to + subnets = [""] + # Name of the CloudWatch log group used to push logs + cloudwatch_log_group_name = "cyral-example-loggroup" + + # Set the allowed CIDR block for SSH access to the sidecar + ssh_inbound_cidr = ["0.0.0.0/0"] + # Set the allowed CIDR block for database access through the + # sidecar + db_inbound_cidr = ["0.0.0.0/0"] + # Set the allowed CIDR block for monitoring requests to the + # sidecar + monitoring_inbound_cidr = ["0.0.0.0/0"] + + # Optionally set the hosted zone ID that will be used to create the + # DNS name in parameter `dns_name` + dns_hosted_zone_id = "" + # Optionally set the DNS name that will be used by your sidecar. Ex: + # sidecar.mycompany.com + dns_name = "" + } +} + +provider "aws" { + region = local.sidecar.region +} + +# Follow the instructions in the Cyral Terraform Provider page to set +# up the credentials: +# +# * https://registry.terraform.io/providers/cyralinc/cyral/latest/docs +provider "cyral" { + client_id = "" + client_secret = "" + + control_plane = local.control_plane_host +} + +# The log group is created in AWS by module.cyral_sidecar +# when the sidecar is deployed. +resource "cyral_integration_logging" "cloudwatch" { + name = "my-cloudwatch" + cloudwatch { + region = local.sidecar.region + group = local.sidecar.cloudwatch_log_group_name + stream = "cyral-sidecar" + } +} + +resource "cyral_sidecar" "sidecar" { + name = "my-sidecar" + deployment_method = "terraform" + activity_log_integration_id = cyral_integration_logging.cloudwatch.id +} + +resource "cyral_sidecar_credentials" "sidecar_credentials" { + sidecar_id = cyral_sidecar.sidecar.id +} + +resource "cyral_repository" "pg" { + name = "pgRepo" + type = "postgresql" + + repo_node { + host = local.repos.pg.host + port = local.repos.pg.port + } +} + +resource "cyral_sidecar_listener" "pg" { + sidecar_id = cyral_sidecar.sidecar.id + repo_types = ["postgresql"] + network_address { + port = local.repos.pg.port + } +} + +resource "cyral_repository_binding" "pg" { + sidecar_id = cyral_sidecar.sidecar.id + repository_id = cyral_repository.pg.id + listener_binding { + listener_id = cyral_sidecar_listener.pg.listener_id + } +} + +data "cyral_integration_idp_saml" "saml" { + display_name = local.idp.name +} + +# Let users from the provided `identity_provider` use SSO +# to access the database +resource "cyral_repository_conf_auth" "pg" { + repository_id = cyral_repository.pg.id + + client_tls = "enable" + repo_tls = "enable" + + identity_provider = data.cyral_integration_idp_saml.saml.idp_list[0].id +} + +# Enables the access portal for this repository in the +# especified sidecar +resource "cyral_repository_access_gateway" "pg" { + repository_id = cyral_repository.pg.id + sidecar_id = cyral_sidecar.sidecar.id + binding_id = cyral_repository_binding.pg.binding_id +} + +########################################################################### +# Creates an IAM policy that the sidecar will assume in order to access +# the RDS instance. In this example, the policy attached to the role will +# let the sidecar connect to all databases in all available accounts and +# regions. +# +# This should NOT be used in production. Refer to the AWS documentation +# for guidance on how to restrict to the database you plan to protect. +# +data "aws_iam_policy_document" "rds_access_policy" { + statement { + actions = ["rds-db:connect"] + resources = [ + "*" + ] + } +} + +resource "aws_iam_policy" "rds_access_policy" { + name = "my-sidecar_access_policy" + path = "/" + description = "Allow sidecar to connect to all RDS instances" + policy = data.aws_iam_policy_document.rds_access_policy.json +} + +data "aws_iam_policy_document" "sidecar_trust_policy" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "AWS" + identifiers = [module.cyral_sidecar.aws_iam_role_arn] + } + } +} + +resource "aws_iam_role" "rds_role" { + name = "my-sidecar_rds_access_role" + path = "/" + assume_role_policy = data.aws_iam_policy_document.sidecar_trust_policy.json +} + +resource "aws_iam_role_policy_attachment" "rds_role_policy_attachment" { + role = aws_iam_role.rds_role.name + policy_arn = aws_iam_policy.rds_access_policy.arn +} +########################################################################### + +resource "cyral_repository_user_account" "pg_repo_user_account" { + # You may opt for a better name here as this is the name that will + # be shown in the UI + name = "my-sidecar_rds_access_role" + repository_id = cyral_repository.pg.id + auth_scheme { + aws_iam { + role_arn = aws_iam_role.rds_role.arn + } + } +} + +# Set the proper identity for the username, email or group that will +# be allowed to access the PG database using SSO +resource "cyral_repository_access_rules" "access_rule" { + repository_id = cyral_repository.pg.id + user_account_id = cyral_repository_user_account.pg_repo_user_account.user_account_id + rule { + identity { + type = "email" + name = "myuser@mycompany.com" + } + } +} + +module "cyral_sidecar" { + source = "cyralinc/sidecar-ec2/aws" + + # Use the module version that is compatible with your sidecar. + version = "~> 4.3" + + sidecar_id = cyral_sidecar.sidecar.id + control_plane = local.control_plane_host + client_id = cyral_sidecar_credentials.sidecar_credentials.client_id + client_secret = cyral_sidecar_credentials.sidecar_credentials.client_secret + + sidecar_ports = [local.repos.pg.port] + + vpc_id = local.sidecar.vpc_id + subnets = local.sidecar.subnets + + ssh_inbound_cidr = local.sidecar.ssh_inbound_cidr + db_inbound_cidr = local.sidecar.db_inbound_cidr + monitoring_inbound_cidr = local.sidecar.monitoring_inbound_cidr + + load_balancer_scheme = local.sidecar.public_sidecar ? "internet-facing" : "internal" + associate_public_ip_address = local.sidecar.public_sidecar + + sidecar_dns_hosted_zone_id = local.sidecar.dns_hosted_zone_id + sidecar_dns_name = local.sidecar.dns_name +} + +output "sidecar_load_balancer_dns" { + value = module.cyral_sidecar.sidecar_load_balancer_dns +} diff --git a/examples/guides/s3_browser_and_aws_cli.tf b/examples/guides/s3_browser_and_aws_cli.tf index 8907bfa8..1691e23d 100644 --- a/examples/guides/s3_browser_and_aws_cli.tf +++ b/examples/guides/s3_browser_and_aws_cli.tf @@ -30,11 +30,6 @@ locals { # internet-facing load balancer (requires a public subnet). public_sidecar = true - # Set the desired sidecar version or leave it empty if - # you prefer to control the version from the control plane - # (later only possible in CPs >=v4.10). - sidecar_version = "v4.10.1" - # Set the AWS region that the sidecar will be deployed to region = "" # Set the ID of VPC that the sidecar will be deployed to @@ -145,7 +140,7 @@ resource "cyral_repository_binding" "s3" { } data "cyral_integration_idp_saml" "saml" { - display_name = local.idp.name + display_name = local.idp.name } # Let users from the provided `identity_provider` use SSO @@ -167,7 +162,10 @@ resource "cyral_repository_access_gateway" "s3" { # Creates an IAM policy that the sidecar will assume in order to access # your S3 bucket. In this example, the policy attached to the role will # let the sidecar access all buckets. - +# +# This should NOT be used in production. Refer to the AWS documentation +# for guidance on how to restrict to the buckets you plan to protect. +# data "aws_iam_policy_document" "s3_access_policy" { statement { actions = ["s3:*"] @@ -236,8 +234,6 @@ module "cyral_sidecar" { # Use the module version that is compatible with your sidecar. version = "~> 4.3" - sidecar_version = local.sidecar.sidecar_version - sidecar_id = cyral_sidecar.sidecar.id control_plane = local.control_plane_host client_id = cyral_sidecar_credentials.sidecar_credentials.client_id diff --git a/templates/guides/iam_auth_rds_pg.md.tmpl b/templates/guides/iam_auth_rds_pg.md.tmpl new file mode 100644 index 00000000..fdfca202 --- /dev/null +++ b/templates/guides/iam_auth_rds_pg.md.tmpl @@ -0,0 +1,29 @@ +--- +page_title: "Authentication from sidecar to RDS using an AWS IAM role" +--- + +-> **Note** This guide assumes you have an RDS PG instance that is +reachable from the subnets the sidecar will be deployed to. Make +sure you create the user in the database that corresponds to the role +created in this example and grant the `rds_iam` permission as shown +in the following command: + +``` +CREATE USER "arn:aws:iam:::role/my-sidecar_rds_access_role"; +GRANT rds_iam TO "arn:aws:iam:::role/my-sidecar_rds_access_role"; +``` + +Use this guide to create the minimum required configuration in both Cyral +Control Plane and your AWS account to deploy a Cyral Sidecar to AWS EC2 +to protect your RDS instance using an IAM role to allow the sidecar to +connect to your database. + +By running this example you will have a fully functional sidecar on your AWS +account. Read the comments and update the necessary parameters as instructed. + +See the [Cyral Sidecar module for AWS EC2](https://registry.terraform.io/modules/cyralinc/sidecar-ec2/aws/latest) +for more details on how the sidecar is deployed to AWS and more advanced configurations. + +See also the official AWS documentation on [IAM database authentication](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html). + +{{ tffile "examples/guides/iam_auth_rds_pg.tf" }} From 7f589d88c196eb01d9d81138d995d7803e543dbd Mon Sep 17 00:00:00 2001 From: Wilson de Carvalho <796900+wcmjunior@users.noreply.github.com> Date: Tue, 13 Feb 2024 13:48:01 -0800 Subject: [PATCH 2/2] Remove < and > signs to avoid HTML rendering issues --- docs/guides/iam_auth_rds_pg.md | 4 ++-- templates/guides/iam_auth_rds_pg.md.tmpl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guides/iam_auth_rds_pg.md b/docs/guides/iam_auth_rds_pg.md index f6aa6a5a..eb7b554a 100644 --- a/docs/guides/iam_auth_rds_pg.md +++ b/docs/guides/iam_auth_rds_pg.md @@ -9,8 +9,8 @@ created in this example and grant the `rds_iam` permission as shown in the following command: ``` -CREATE USER "arn:aws:iam:::role/my-sidecar_rds_access_role"; -GRANT rds_iam TO "arn:aws:iam:::role/my-sidecar_rds_access_role"; +CREATE USER "arn:aws:iam::YOUR_AWS_ACCOUNT_NUM:role/my-sidecar_rds_access_role"; +GRANT rds_iam TO "arn:aws:iam::YOUR_AWS_ACCOUNT_NUM:role/my-sidecar_rds_access_role"; ``` Use this guide to create the minimum required configuration in both Cyral diff --git a/templates/guides/iam_auth_rds_pg.md.tmpl b/templates/guides/iam_auth_rds_pg.md.tmpl index fdfca202..37773f6a 100644 --- a/templates/guides/iam_auth_rds_pg.md.tmpl +++ b/templates/guides/iam_auth_rds_pg.md.tmpl @@ -9,8 +9,8 @@ created in this example and grant the `rds_iam` permission as shown in the following command: ``` -CREATE USER "arn:aws:iam:::role/my-sidecar_rds_access_role"; -GRANT rds_iam TO "arn:aws:iam:::role/my-sidecar_rds_access_role"; +CREATE USER "arn:aws:iam::YOUR_AWS_ACCOUNT_NUM:role/my-sidecar_rds_access_role"; +GRANT rds_iam TO "arn:aws:iam::YOUR_AWS_ACCOUNT_NUM:role/my-sidecar_rds_access_role"; ``` Use this guide to create the minimum required configuration in both Cyral