diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d532a33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ + +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# tf lock files +.terraform.lock.hcl + +# Crash log files +crash.log + +# Ignore any .tfvars files that are generated automatically for each Terraform run. Most +# .tfvars files are managed as part of configuration and so should be included in +# version control. +# +# example.tfvars + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +.DS_Store +.vscode/ +.idea/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..47e8ea5 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# StreamNative Managed Cloud +This repository contains Terraform modules for the management of StreamNative's vendor access into a Cloud Provider. + +Previous verions of these modules can be found in the following locations: +- [terraform-aws-cloud//modules/managed-cloud?ref=v2.5.0](https://github.com/streamnative/terraform-aws-cloud/tree/v2.5.0-alpha/modules/managed-cloud): This was the original location of the AWS vendor access module, which has been moved to this repository. The last version released to the Terraform Registry was `v2.5.0-alpha`. +- [https://github.com/streamnative/terraform-aws-managed-cloud](https://github.com/streamnative/terraform-aws-managed-cloud): This repository contains an older AWS vendor access module, which has been deprecated and is no longer in use. + +## Modules +The modules are organized by Cloud Provider. For example, the AWS modules are in the `modules/aws` directory and the GCP modules (WIP) modules are in the `modules/gcp`, and so on. + +## Examples +Examples of the modules can be found in the `examples` directory. + +Details on the modules themselves and their requirements can be found in their respective README files, contained in the `modules` directory. + +## Upgrading an existing AWS module +If you have used the previous version of the AWS vendor access module, your configuration should have looked something like this: + +```hcl +module "sn_managed_cloud" { + source = "github.com/streamnative/terraform-aws-cloud//modules/managed-cloud?ref=v2.5.0-alpha" + + external_id = "o-kxb4r" + runtime_hosted_zone_allowed_ids = ["arn:aws:route53:::hostedzone/Z00048871IAX8IX9HGD0"] + region = "us-west-2" + use_runtime_policy = true + +} +``` + +Upgrading to this version of the module is quite simple, but does involve a few minor changes. + +- The `source` URL has changed to `github.com/streamnative/terraform--managed-cloud//modules/aws?ref=v3.0.0` (note the tag reference, which as of this writing is `v3.0.0`). +- `use_runtime_poliy` has been removed, as it is now the default behavior. +- `runtime_hosted_zone_allowed_ids` has been renamed to `hosted_zone_allowed_ids`, and it now properly accepts a list of IDs for your hosted zones, rather than the full ARNs. + +With these changes in mind, your configuration should now look like this: + +```hcl +module "sn_managed_cloud" { + source = "github.com/streamnative/terraform-managed-cloud//modules/managed-cloud?ref=v2.5.0-alpha" + + external_id = "o-kxb4r" + hosted_zone_allowed_ids = ["Z00048871IAX8IX9HGD0"] + region = "us-west-2" + +} +``` + +After making changes to your configuration, you can run `terraform init` to download the new module, and then `terraform apply` to apply the changes. + +In most cases, you will see the module wanting to change 7 resources (the total number of resources created by this module, if `use_runtime_policy` was set to `true`). + +Most of the changes are in the IAM policies, which allow for compatability with the [v3.0.0 release](https://github.com/streamnative/terraform-aws-cloud/pull/91) of the `terraform-aws-cloud` module (this Terraform module is used for creating a StreamNative Cloud EKS environment). + +If you have questions or concerns with these changes, please reach out to your StreamNative account representative. \ No newline at end of file diff --git a/examples/aws/main.tf b/examples/aws/main.tf new file mode 100644 index 0000000..8c72417 --- /dev/null +++ b/examples/aws/main.tf @@ -0,0 +1,13 @@ +provider "aws" { + region = "us-west-2" +} + +module "aws-managed-cloud" { + source = "../../modules/aws" + + external_id = "o-kxb4r" + hosted_zone_allowed_ids = ["Z00048871IAX8IX9HGD0"] + region = "us-west-2" + write_policy_files = true # Writes the rendered policy files to the `policy_files` directory, found in this example + +} diff --git a/examples/aws/policy_files/alb_policy.json b/examples/aws/policy_files/alb_policy.json new file mode 100755 index 0000000..30562ba --- /dev/null +++ b/examples/aws/policy_files/alb_policy.json @@ -0,0 +1,227 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "iam:CreateServiceLinkedRole" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "iam:AWSServiceName": "elasticloadbalancing.amazonaws.com" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "ec2:DescribeAccountAttributes", + "ec2:DescribeAddresses", + "ec2:DescribeAvailabilityZones", + "ec2:DescribeInternetGateways", + "ec2:DescribeVpcs", + "ec2:DescribeVpcPeeringConnections", + "ec2:DescribeSubnets", + "ec2:DescribeSecurityGroups", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeTags", + "ec2:GetCoipPoolUsage", + "ec2:DescribeCoipPools", + "elasticloadbalancing:DescribeLoadBalancers", + "elasticloadbalancing:DescribeLoadBalancerAttributes", + "elasticloadbalancing:DescribeListeners", + "elasticloadbalancing:DescribeListenerCertificates", + "elasticloadbalancing:DescribeSSLPolicies", + "elasticloadbalancing:DescribeRules", + "elasticloadbalancing:DescribeTargetGroups", + "elasticloadbalancing:DescribeTargetGroupAttributes", + "elasticloadbalancing:DescribeTargetHealth", + "elasticloadbalancing:DescribeTags" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "cognito-idp:DescribeUserPoolClient", + "acm:ListCertificates", + "acm:DescribeCertificate", + "iam:ListServerCertificates", + "iam:GetServerCertificate", + "waf-regional:GetWebACL", + "waf-regional:GetWebACLForResource", + "waf-regional:AssociateWebACL", + "waf-regional:DisassociateWebACL", + "wafv2:GetWebACL", + "wafv2:GetWebACLForResource", + "wafv2:AssociateWebACL", + "wafv2:DisassociateWebACL", + "shield:GetSubscriptionState", + "shield:DescribeProtection", + "shield:CreateProtection", + "shield:DeleteProtection" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:RevokeSecurityGroupIngress" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateSecurityGroup" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateTags" + ], + "Resource": "arn:aws:ec2:*:*:security-group/*", + "Condition": { + "StringEquals": { + "ec2:CreateAction": "CreateSecurityGroup" + }, + "Null": { + "aws:RequestTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateTags", + "ec2:DeleteTags" + ], + "Resource": "arn:aws:ec2:*:*:security-group/*", + "Condition": { + "Null": { + "aws:RequestTag/elbv2.k8s.aws/cluster": "true", + "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:RevokeSecurityGroupIngress", + "ec2:DeleteSecurityGroup" + ], + "Resource": "*", + "Condition": { + "Null": { + "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" + }, + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:CreateLoadBalancer", + "elasticloadbalancing:CreateTargetGroup" + ], + "Resource": "*", + "Condition": { + "Null": { + "aws:RequestTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:CreateListener", + "elasticloadbalancing:DeleteListener", + "elasticloadbalancing:CreateRule", + "elasticloadbalancing:DeleteRule" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:AddTags", + "elasticloadbalancing:RemoveTags" + ], + "Resource": [ + "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", + "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", + "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*" + ], + "Condition": { + "Null": { + "aws:RequestTag/elbv2.k8s.aws/cluster": "true", + "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:AddTags", + "elasticloadbalancing:RemoveTags" + ], + "Resource": [ + "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*", + "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", + "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*", + "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:ModifyLoadBalancerAttributes", + "elasticloadbalancing:SetIpAddressType", + "elasticloadbalancing:SetSecurityGroups", + "elasticloadbalancing:SetSubnets", + "elasticloadbalancing:DeleteLoadBalancer", + "elasticloadbalancing:ModifyTargetGroup", + "elasticloadbalancing:ModifyTargetGroupAttributes", + "elasticloadbalancing:DeleteTargetGroup" + ], + "Resource": "*", + "Condition": { + "Null": { + "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:RegisterTargets", + "elasticloadbalancing:DeregisterTargets" + ], + "Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:SetWebAcl", + "elasticloadbalancing:ModifyListener", + "elasticloadbalancing:AddListenerCertificates", + "elasticloadbalancing:RemoveListenerCertificates", + "elasticloadbalancing:ModifyRule" + ], + "Resource": "*" + } + ] +} diff --git a/examples/aws/policy_files/bootstrap_policy.json b/examples/aws/policy_files/bootstrap_policy.json new file mode 100755 index 0000000..524821d --- /dev/null +++ b/examples/aws/policy_files/bootstrap_policy.json @@ -0,0 +1,337 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "UnResRW", + "Effect": "Allow", + "Action": [ + "kms:CreateAlias", + "kms:DeleteAlias", + "kms:ScheduleKeyDeletion", + "logs:CreateLogGroup", + "logs:PutRetentionPolicy", + "route53:CreateHostedZone", + "route53:ChangeTagsForResource", + "support:*", + "servicequotas:List*", + "servicequotas:Get*" + ], + "Resource": "*" + }, + { + "Sid": "RO", + "Effect": "Allow", + "Action": [ + "acm:ImportCertificate", + "acm:ListCertificates", + "acm:ListTagsForCertificate", + "autoscaling:Describe*", + "ec2:Describe*", + "ec2:Get*", + "eks:Describe*", + "eks:List*", + "elasticloadbalancing:Describe*", + "iam:GetInstanceProfile", + "iam:GetOpenIDConnectProvider", + "iam:GetPolicy", + "iam:GetPolicyVersion", + "iam:GetRole", + "iam:List*", + "kms:DescribeKey", + "kms:GetKeyPolicy", + "kms:GetKeyRotationStatus", + "kms:ListAliases", + "kms:ListResourceTags", + "logs:Describe*", + "logs:List*", + "route53:Get*", + "route53:List*", + "s3:ListAllMyBuckets", + "s3:ListBucket" + ], + "Resource": "*" + }, + { + "Sid": "ResRlPol", + "Effect": "Allow", + "Action": "iam:AttachRolePolicy", + "Resource": "arn:aws:iam::1234567890123:role/StreamNative/*" + }, + { + "Sid": "SecGrpVPC", + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroup*", + "ec2:RevokeSecurityGroup*" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "RunInst", + "Effect": "Allow", + "Action": [ + "ec2:RunInstances" + ], + "Resource": "*", + "Condition": { + "ArnLikeIfExists": { + "ec2:Vpc": ["arn:aws:ec2:*:1234567890123:vpc/*"] + } + } + }, + { + "Sid": "ResR53Z", + "Effect": "Allow", + "Action": [ + "route53:ChangeResourceRecordSets" + ], + "Resource": ["arn:aws:route53:::hostedzone/*"] + }, + { + "Sid": "ResEKS", + "Effect": "Allow", + "Action": [ + "eks:DeleteNodeGroup" + ], + "Resource": [ + "arn:aws:eks:*:1234567890123:nodegroup/*/*snc*/*" + ] + }, + { + "Sid": "AsgTags", + "Effect": "Allow", + "Action": [ + "autoscaling:*Tags", + "autoscaling:Delete*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "autoscaling:ResourceTag/cluster-name": "*snc*" + } + } + }, + { + "Sid": "EC2Tags", + "Effect": "Allow", + "Action": [ + "ec2:Associate*", + "ec2:Delete*", + "ec2:Disassociate*", + "ec2:Modify*", + "ec2:*TransitGateway*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "ec2:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "ELBTags", + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:De*", + "elasticloadbalancing:*LoadBalancer*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "elasticloadbalancing:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "AllowTag", + "Effect": "Allow", + "Action": [ + "eks:TagResource", + "eks:UntagResource" + ], + "Resource": "*", + "Condition": { + "StringLike": { + "aws:ResourceTag/cluster-name": "*snc*" + } + } + }, + { + "Sid": "ReqReqTag", + "Effect": "Allow", + "Action": [ + "acm:AddTagsToCertificate", + "acm:ImportCertificate", + "acm:RemoveTagsFromCertificate", + "acm:RequestCertificate", + "autoscaling:Create*", + "ec2:*TransitGateway*", + "ec2:AllocateAddress", + "ec2:Create*", + "eks:Create*", + "eks:RegisterCluster", + "eks:TagResource", + "elasticloadbalancing:Add*", + "kms:CreateKey", + "kms:TagResource" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:RequestTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "ReqResrcTag", + "Effect": "Allow", + "Action": [ + "acm:DeleteCertificate", + "acm:DescribeCertificate", + "acm:ExportCertificate", + "acm:GetCertificate", + "acm:ImportCertificate", + "acm:RemoveTagsFromCertificate", + "acm:ResendValidationEmail", + "autoscaling:AttachInstances", + "autoscaling:CreateOrUpdateTags", + "autoscaling:Detach*", + "autoscaling:Update*", + "autoscaling:Resume*", + "autoscaling:Suspend*", + "autoscaling:SetDesired*", + "ec2:AssignPrivateIpAddresses", + "ec2:AttachInternetGateway", + "ec2:CreateLaunchTemplateVersion", + "ec2:CreateNatGateway", + "ec2:CreateNetworkInterface", + "ec2:CreateRoute", + "ec2:CreateRouteTable", + "ec2:CreateSecurityGroup", + "ec2:CreateSubnet", + "ec2:CreateTags", + "ec2:CreateVpcEndpoint", + "ec2:Detach*", + "ec2:Release*", + "ec2:Revoke*", + "ec2:TerminateInstances", + "ec2:Update*", + "eks:DeleteAddon", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", + "eks:DeregisterCluster", + "eks:U*", + "elasticloadbalancing:*Listener", + "elasticloadbalancing:*Rule", + "elasticloadbalancing:*TargetGroup", + "elasticloadbalancing:Set*", + "elasticloadbalancing:Re*", + "logs:DeleteLogGroup", + "logs:PutRetentionPolicy" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "ResS3", + "Effect": "Allow", + "Action":[ + "s3:CreateBucket", + "s3:Delete*", + "s3:Get*", + "s3:List*", + "s3:PutBucket*", + "s3:PutObject*", + "s3:PutLifecycle*", + "s3:PutAccelerateConfiguration", + "s3:PutAccessPointPolicy", + "s3:PutAccountPublicAccessBlock", + "s3:PutAnalyticsConfiguration", + "s3:PutEncryptionConfiguration" + ], + "Resource": [ + "arn:aws:s3:::*snc*" + ] + }, + { + "Sid": "IAMReqTag", + "Effect": "Allow", + "Action": [ + "iam:AddRoleToInstanceProfile", + "iam:DeleteInstanceProfile", + "iam:DeleteOpenIDConnectProvider", + "iam:DeleteRole", + "iam:DeleteServiceLinkedRole", + "iam:DetachRolePolicy", + "iam:PutRolePermissionsBoundary", + "iam:RemoveRoleFromInstanceProfile", + "iam:SetDefaultPolicyVersion", + "iam:UpdateAssumeRolePolicy", + "iam:UpdateOpenIDConnectProviderThumbprint", + "iam:UpdateRole", + "iam:UpdateRoleDescription", + "iam:Untag*", + "iam:CreateOpenIDConnectProvider", + "iam:TagPolicy", + "iam:TagRole", + "iam:TagInstanceProfile", + "iam:TagOpenIDConnectProvider", + "iam:DeletePolicy", + "iam:DeletePolicyVersion" + ], + "Resource": [ + "arn:aws:iam::1234567890123:role/StreamNative/*", + "arn:aws:iam::1234567890123:policy/StreamNative/*", + "arn:aws:iam::1234567890123:oidc-provider/*" + ], + "Condition": { + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "SvcLnkRl", + "Effect": "Allow", + "Action": "iam:CreateServiceLinkedRole", + "Resource": "arn:aws:iam::1234567890123:role/aws-service-role/*" + }, + { + "Sid": "ResPsRlEKS", + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": [ + "arn:aws:iam::1234567890123:role/*snc*" + ], + "Condition": { + "StringEquals": { + "iam:PassedToService": "eks.amazonaws.com" + } + } + }, + { + "Sid": "RqPBRls", + "Effect": "Allow", + "Action": [ + "iam:CreateRole" + ], + "Resource": "arn:aws:iam::1234567890123:role/StreamNative/*", + "Condition": { + "StringEqualsIgnoreCase": { + "iam:PermissionsBoundary": "arn:aws:iam:::policy/StreamNative/StreamNativeCloudPermissionBoundary" + } + } + } + ] +} diff --git a/examples/aws/policy_files/management_policy.json b/examples/aws/policy_files/management_policy.json new file mode 100755 index 0000000..100ddb7 --- /dev/null +++ b/examples/aws/policy_files/management_policy.json @@ -0,0 +1,191 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowedServices", + "Effect": "Allow", + "Action": [ + "acm:List*", + "acm:ImportCertificate", + "cloudwatch:Describe*", + "cloudwatch:List*", + "cloudwatch:Get*", + "logs:Describe*", + "logs:List*", + "logs:Filter*", + "logs:StartQuery", + "logs:StopQuery", + "route53:Get*", + "route53:List*", + "support:*", + "servicequotas:List*", + "servicequotas:Get*" + ], + "Resource": "*" + }, + { + "Sid": "AsgTags", + "Effect": "Allow", + "Action": [ + "autoscaling:Describe*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "autoscaling:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "EC2Tags", + "Effect": "Allow", + "Action": [ + "ec2:Describe*", + "ec2:Get*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "ec2:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "ELBTags", + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:Describe*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "elasticloadbalancing:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "EKSTags", + "Effect": "Allow", + "Action": [ + "eks:Describe*", + "eks:List*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "eks:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "AllowedIAMReadActions", + "Effect": "Allow", + "Action": [ + "iam:GetPolicy*", + "iam:GetRole*", + "iam:ListRole*", + "iam:ListPolic*" + ], + "Resource": [ + "arn:aws:iam::1234567890123:role/StreamNative/*", + "arn:aws:iam::1234567890123:policy/StreamNative/*", + "arn:aws:iam::aws:policy/*" + ] + }, + { + "Sid": "IamRequireRequestTag", + "Effect": "Allow", + "Action": [ + "iam:CreateRole", + "iam:TagRole" + ], + "Resource": [ + "arn:aws:iam::1234567890123:role/StreamNative/*" + ], + "Condition": { + "StringEqualsIgnoreCase": { + "aws:RequestTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "IamAttach", + "Effect": "Allow", + "Action": [ + "iam:AttachRolePolicy" + ], + "Resource": "arn:aws:iam::1234567890123:role/StreamNative/*", + "Condition": { + "ArnEquals": { + "iam:PolicyARN": [ + "arn:aws:iam::1234567890123:policy/StreamNative/StreamNativeCloudManagementPolicy" + ] + } + } + }, + { + "Sid": "IamRequireResourceTag", + "Effect": "Allow", + "Action": [ + "iam:DeleteRole", + "iam:DetachRolePolicy", + "iam:PutRolePermissionsBoundary", + "iam:SetDefaultPolicyVersion", + "iam:UpdateAssumeRolePolicy", + "iam:UpdateRole", + "iam:UpdateRoleDescription" + ], + "Resource": [ + "arn:aws:iam::1234567890123:role/StreamNative/*", + "arn:aws:iam::1234567890123:policy/StreamNative/*" + ], + "Condition": { + "StringEqualsIgnoreCase": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "RequireResourceTag", + "Effect": "Allow", + "Action": [ + "acm:DeleteCertificate", + "acm:DescribeCertificate", + "acm:GetCertificate", + "autoscaling:CancelInstanceRefresh", + "autoscaling:PutScalingPolicy", + "autoscaling:ResumeProcesses", + "autoscaling:SetDesiredCapacity", + "autoscaling:StartInstanceRefresh", + "autoscaling:SuspendProcesses", + "autoscaling:UpdateAutoScalingGroup", + "eks:UpdateNodegroupConfig", + "eks:UpdateNodegroupVersion" + ], + "Resource": [ + "*" + ], + "Condition": { + "StringEqualsIgnoreCase": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "RequireRequestTag", + "Effect": "Allow", + "Action": [ + "acm:AddTagsToCertificate", + "acm:ImportCertificate" + ], + "Resource": [ + "*" + ], + "Condition": { + "StringEqualsIgnoreCase": { + "aws:RequestTag/Vendor": "StreamNative" + } + } + } + ] +} diff --git a/examples/aws/policy_files/permission_boundary_policy.json b/examples/aws/policy_files/permission_boundary_policy.json new file mode 100755 index 0000000..0a5c20c --- /dev/null +++ b/examples/aws/policy_files/permission_boundary_policy.json @@ -0,0 +1,147 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowedServices", + "Effect": "Allow", + "Action": [ + "acm:*", + "autoscaling:*", + "cognito-idp:*", + "dynamodb:*", + "ec2:*", + "ecr:*", + "eks:*", + "elasticloadbalancing:*", + "iam:GetInstanceProfile", + "iam:GetOpenIDConnectProvider", + "iam:GetPolicy", + "iam:GetPolicyVersion", + "iam:GetRole", + "iam:GetServerCertificate", + "iam:ListAttachedRolePolicies", + "iam:ListEntitiesForPolicy", + "iam:ListInstanceProfile*", + "iam:ListOpenIDConnectProvider*", + "iam:ListPolicies", + "iam:ListPolicyTags", + "iam:ListPolicyVersions", + "iam:ListRole*", + "iam:ListServerCertificates", + "kms:*", + "logs:*", + "route53:*", + "s3:*", + "servicequotas:*", + "shield:*", + "support:*", + "sts:*", + "waf-regional:*", + "wafv2:*" + ], + "Resource": "*" + }, + { + "Sid": "IamRestrictions", + "Effect": "Allow", + "Action": [ + "iam:AddRoleToInstanceProfile", + "iam:CreateOpenIDConnectProvider", + "iam:CreateRole", + "iam:CreateServiceLinkedRole", + "iam:DeleteInstanceProfile", + "iam:DeleteOpenIDConnectProvider", + "iam:DeletePolicy", + "iam:DeletePolicyVersion", + "iam:DeleteRole", + "iam:DeleteServiceLinkedRole", + "iam:DetachRolePolicy", + "iam:PassRole", + "iam:PutRolePermissionsBoundary", + "iam:RemoveRoleFromInstanceProfile", + "iam:SetDefaultPolicyVersion", + "iam:TagInstanceProfile", + "iam:TagOpenIDConnectProvider", + "iam:TagPolicy", + "iam:TagRole", + "iam:Untag*", + "iam:UpdateAssumeRolePolicy", + "iam:UpdateOpenIDConnectProviderThumbprint", + "iam:UpdateRole", + "iam:UpdateRoleDescription" + ], + "Resource": [ + "arn:aws:iam::aws:policy/*", + "arn:aws:iam::1234567890123:role/aws-service-role/*", + "arn:aws:iam::1234567890123:role/*snc*", + "arn:aws:iam::1234567890123:role/StreamNative/*", + "arn:aws:iam::1234567890123:policy/StreamNative/*", + "arn:aws:iam::1234567890123:oidc-provider/*", + "arn:aws:iam::1234567890123:instance-profile/*", + "arn:aws:iam::1234567890123:server-certificate/*" + ] + }, + { + "Sid": "RestrictPassRoleToEKS", + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": "arn:aws:iam::1234567890123:role/*snc*", + "Condition": { + "StringEquals": { + "iam:PassedToService": "eks.amazonaws.com" + } + } + }, + { + "Sid": "AllowedIAMManagedPolicies", + "Effect": "Allow", + "Action": [ + "iam:AttachRolePolicy" + ], + "Resource": "arn:aws:iam::1234567890123:role/StreamNative/*", + "Condition": { + "ForAnyValue:ArnLike": { + "iam:PolicyARN": [ "arn:aws:iam::1234567890123:policy/StreamNative/*", "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", "arn:aws:iam::aws:policy/AmazonEKSServicePolicy", "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController", "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy", "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy", "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy" ] + } + } + }, + { + "Sid": "RequirePermissionBoundaryForIamRoles", + "Effect": "Allow", + "Action": [ + "iam:CreateRole" + ], + "Resource": "arn:aws:iam::1234567890123:role/StreamNative/*", + "Condition": { + "StringEqualsIgnoreCase": { + "aws:ResourceTag/Vendor": "StreamNative", + "iam:PermissionsBoundary": "arn:aws:iam:::policy/StreamNative/StreamNativeCloudPermissionBoundary" + } + } + }, + { + "Sid": "RestrictChangesToVendorAccess", + "Effect": "Deny", + "Action": [ + "iam:Create*", + "iam:Delete*", + "iam:Put*", + "iam:Tag*", + "iam:Untag*", + "iam:Update*", + "iam:Set*" + ], + "Resource": [ + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudBootstrapPolicy", + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudLBPolicy", + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudManagementPolicy", + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudPermissionBoundary", + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudRuntimePolicy", + "arn:aws:iam::1234567890123:role/StreamNative/StreamNativeBootstrapRole", + "arn:aws:iam::1234567890123:role/StreamNative/StreamNativeManagementRole" + ] + } + ] +} diff --git a/examples/aws/policy_files/runtime_policy.json b/examples/aws/policy_files/runtime_policy.json new file mode 100755 index 0000000..a537e15 --- /dev/null +++ b/examples/aws/policy_files/runtime_policy.json @@ -0,0 +1,138 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ro", + "Effect": "Allow", + "Action": [ + "secretsmanager:ListSecrets", + "route53:ListTagsForResource", + "route53:ListResourceRecordSets", + "route53:ListHostedZones*", + "route53:GetChange", + "ec2:DescribeVolumesModifications", + "ec2:DescribeVolumes", + "ec2:DescribeTags", + "ec2:DescribeSnapshots", + "autoscaling:Describe*" + ], + "Resource": ["*"] + }, + { + "Sid": "r53sc", + "Effect": "Allow", + "Action": "route53:ChangeResourceRecordSets", + "Resource": ["arn:aws:route53:::hostedzone/*"] + }, + { + "Sid": "asg", + "Effect": "Allow", + "Action": [ + "autoscaling:UpdateAutoScalingGroup", + "autoscaling:TerminateInstanceInAutoScalingGroup", + "autoscaling:SetDesiredCapacity" + ], + "Resource": "*", + "Condition": { + "StringLike": { + "autoscaling:ResourceTag/eks:cluster-name": "*snc*" + } + } + }, + { + "Sid": "csik1", + "Effect": "Allow", + "Action": [ + "kms:RevokeGrant", + "kms:ListGrants", + "kms:CreateGrant" + ], + "Resource": [ "arn:aws:kms:us-west-2:1234567890123:key/7f6c7a67-5c0a-4be4-8c87-047288a9c37b", "arn:aws:kms:us-west-2:1234567890123:key/a2b08e48-ba16-48b0-ad72-8dfc38198d75" ], + "Condition": { + "Bool": { + "kms:GrantIsForAWSResource": [ + "true" + ] + } + } + }, + { + "Sid": "csik2", + "Effect": "Allow", + "Action": [ + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:Encrypt", + "kms:DescribeKey", + "kms:Decrypt" + ], + "Resource": [ "arn:aws:kms:us-west-2:1234567890123:key/7f6c7a67-5c0a-4be4-8c87-047288a9c37b", "arn:aws:kms:us-west-2:1234567890123:key/a2b08e48-ba16-48b0-ad72-8dfc38198d75" ] + }, + { + "Sid": "s3b", + "Effect": "Allow", + "Action": [ + "s3:ListMultipart*", + "s3:ListBucket" + ], + "Resource": "arn:aws:s3:::*snc*" + }, + { + "Sid": "s3o", + "Effect": "Allow", + "Action": [ + "s3:Put*", + "s3:List*", + "s3:*Object", + "s3:*Multipart*" + ], + "Resource": "arn:aws:s3:::*snc*" + }, + { + "Sid": "vbc", + "Effect": "Allow", + "Action": [ + "ec2:CreateVolume", + "ec2:CreateSnapshot" + ], + "Resource": "*", + "Condition": { + "StringLike": { + "aws:RequestTag/kubernetes.io/cluster/*snc*": [ + "owned" + ] + } + } + }, + { + "Sid": "vbt", + "Effect": "Allow", + "Action": "ec2:CreateTags", + "Resource": [ + "arn:aws:ec2:*:*:volume/*", + "arn:aws:ec2:*:*:snapshot/*" + ], + "Condition": { + "StringEquals": { + "ec2:CreateAction": [ + "CreateVolume", + "CreateSnapshot" + ] + } + } + }, + { + "Sid": "vbd", + "Effect": "Allow", + "Action": "ec2:DeleteSnapshot", + "Resource": "*", + "Condition": { + "StringLike": { + "aws:ResourceTag/kubernetes.io/cluster/*snc*": [ + "owned" + ] + } + } + } + ] +} \ No newline at end of file diff --git a/modules/aws/README.md b/modules/aws/README.md new file mode 100644 index 0000000..8f48325 --- /dev/null +++ b/modules/aws/README.md @@ -0,0 +1,1542 @@ +# StreamNative Cloud - Managed AWS Vendor Access +This Terraform module creates IAM resources within your AWS account. These resources give StreamNative access only for the provisioning and management of StreamNative's Managed Cloud offering. + +For more information about StreamNative and our managed offerings for Apache Pulsar, visit our [website](https://streamnative.io/streamnativecloud/). + +## Module Overview +This module creates the following resources within your AWS account: + +- `StreamNativeCloudPermissionBoudary`: The [permission boundary](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html) defines the scope of possible AWS actions and resources StreamNative is authorized to perform and use within your AWS account. + - It is self-enforcing and required for any IAM Role created by StreamNative + - Sets which IAM policies and expected EKS cluster resources StreamNative is allowed to work with + - Prevents privilege escalation + +- `role/StreamNativeCloudManagementRole` & `role/StreamNativeCloudManagementPolicy`: These IAM resources are used for the day-to-day management of the StreamNative managed infrastructure in your AWS account. This role and policy have the following characteristics: + - Limited in their ability to create, modify, and delete resources within AWS + - Authorized to fully manage StreamNative owned EKS cluster, worker nodes, and load balancers + +- `role/StreamNativeCloudBootstrapRole` & `policy/StreamNativeCloudBootstrapPolicy`: These IAM resources are used for provisioning, deprovisioning, and regular or emergency maintenance. This role and policy have the following characteristics: + - Have the ability to create, delete, manage, and read (within the limits of the permission boundary) EC2, EKS, IAM, DynamoDB, Route53, and KMS resources + - Cannot create or modify IAM policies (but are allowed to work with IAM policies specified by this module) + - Can only work with resources that have specific tags associated or certain expected patterns in the resource's friendly name. + +- `policy/StreamNativeCloudRuntimePolicy` & `policy/StreamNativeCloudLbPolicy`: These policies are needed by add-ons running within EKS that require an [IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) for interacting with AWS services. The EKS add-ons we install include: + - [aws-ebs-csi-driver](https://github.com/kubernetes-sigs/aws-ebs-csi-driver): Manages the lifecycle of EBS volumes used by Apache Pulsar running within EKS + - [aws-load-balanacer-controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.4/): Used for managing external ingress resources within EKS, such as Network Load Balancers + - [certificate-manager](https://github.com/cert-manager/cert-manager): Manages TLS certificates within the cluster, requiring Route53 access for validating domain ownership + - [cluster-autoscaler](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md): Examines and modifies EC2 autoscaling groups for the EKS cluster based on resource utilization + - [external-dns](https://github.com/kubernetes-sigs/external-dns): Manages DNS records within EKS in a delegated Route53 Public Hosted Zone + - [velero](https://github.com/vmware-tanzu/velero): Used for backups of Kubernetes resources and EBS volumes to S3 + +## Usage +To use this module you must have [Terraform installed](https://learn.hashicorp.com/tutorials/terraform/install-cli) and be [familiar](https://learn.hashicorp.com/collections/terraform/aws-get-started) with its usage for AWS. It is recommended to securely store the Terraform configuration you create in source control, as well as use [Terraform's Remote State](https://www.terraform.io/language/state/remote) for storing the `*.tfstate` file. + +### Pre Requisites +This module requires only one input to function: + +- `external_ids`: A list of [external IDs](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) that correspond to your [Organization IDs](https://docs.streamnative.io/cloud/stable/concepts/concepts#organizations) within StreamNative Cloud. Our services use this ID for any [STS assume role calls](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) to IAM roles created by the module. To find your Organization ID(s), please refer to our [documentation](https://docs.streamnative.io/cloud/stable/use/organization). + +### Optional Inputs + +- `additional_iam_policy_arns`: A list of IAM policies within your AWS account that StreamNative is authorized to work with. Typically this is not required, but may be necessary if third party software (such as your own APM or monitoring tooling) is needed on the cluster. + - Note: By default, our IAM roles can attach any IAM policy created under the `/StreamNative/` [IAM path](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-friendly-names) with the default policies created by this module. If you need a custom policy, create one under the root path `/StreamNative/` and it will implicitly be made available for use without needing to specify this input. + +### Get Started + +Start by writing the following configuration to a new file `main.tf` containing the following Terraform code: + +```hcl + +provider "aws" { + region = +} + +module "sn_managed_cloud" { + source = "streamnative/managed-cloud//modules/aws" + + region = + hosted_zone_allowed_ids = + external_ids = [ "" ] + +} +``` + +After [authenticating to your AWS account](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration) execute the following sequence of commands from the directory containing the `main.tf` configuration file: + +1. `terraform init` + +
(example output)

+ +```bash +$ terraform init + +Initializing modules... +- sn_managed_cloud in ../aws + +Initializing the backend... + +Initializing provider plugins... +- Finding hashicorp/aws versions matching ">= 4.32.0"... +- Finding latest version of hashicorp/local... +- Installing hashicorp/local v2.2.3... +- Installed hashicorp/local v2.2.3 (signed by HashiCorp) +- Installing hashicorp/aws v4.32.0... +- Installed hashicorp/aws v4.32.0 (signed by HashiCorp) + +Terraform has created a lock file .terraform.lock.hcl to record the provider +selections it made above. Include this file in your version control repository +so that Terraform can guarantee to make the same selections by default when +you run "terraform init" in the future. + +Terraform has been successfully initialized! + +You may now begin working with Terraform. Try running "terraform plan" to see +any changes that are required for your infrastructure. All Terraform commands +should now work. + +If you ever set or change modules or backend configuration for Terraform, +rerun this command to reinitialize your working directory. If you forget, other +commands will detect it and remind you to do so if necessary. +``` +

+ +2. `terraform plan` + +
(example output)

+ +``` +$ terraform plan + +module.aws-managed-cloud.data.aws_caller_identity.current: Reading... +module.aws-managed-cloud.data.aws_partition.current: Reading... +module.aws-managed-cloud.data.aws_kms_key.s3_default: Reading... +module.aws-managed-cloud.data.aws_kms_key.ebs_default: Reading... +module.aws-managed-cloud.data.aws_iam_policy_document.streamnative_vendor_access: Reading... +module.aws-managed-cloud.data.aws_partition.current: Read complete after 0s [id=aws] +module.aws-managed-cloud.data.aws_iam_policy_document.streamnative_control_plane_access: Reading... +module.aws-managed-cloud.data.aws_iam_policy_document.streamnative_vendor_access: Read complete after 0s [id=1415275062] +module.aws-managed-cloud.data.aws_iam_policy_document.streamnative_control_plane_access: Read complete after 0s [id=385961959] +module.aws-managed-cloud.data.aws_kms_key.ebs_default: Read complete after 0s [id=7f6c7a67-5c0a-4be4-8c87-047288a9c37b] +module.aws-managed-cloud.data.aws_kms_key.s3_default: Read complete after 0s [id=a2b08e48-ba16-48b0-ad72-8dfc38198d75] +module.aws-managed-cloud.data.aws_caller_identity.current: Read complete after 0s [id=123456789012] + +Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + + create + +Terraform will perform the following actions: + + # module.aws-managed-cloud.aws_iam_policy.alb_policy will be created + + resource "aws_iam_policy" "alb_policy" { + + arn = (known after apply) + + description = "The AWS policy as defined by https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.1/docs/install/iam_policy.json" + + id = (known after apply) + + name = "StreamNativeCloudLBPolicy" + + path = "/StreamNative/" + + policy = jsonencode( + { + + Statement = [ + + { + + Action = [ + + "iam:CreateServiceLinkedRole", + ] + + Condition = { + + StringEquals = { + + "iam:AWSServiceName" = "elasticloadbalancing.amazonaws.com" + } + } + + Effect = "Allow" + + Resource = "*" + }, + + { + + Action = [ + + "ec2:DescribeAccountAttributes", + + "ec2:DescribeAddresses", + + "ec2:DescribeAvailabilityZones", + + "ec2:DescribeInternetGateways", + + "ec2:DescribeVpcs", + + "ec2:DescribeVpcPeeringConnections", + + "ec2:DescribeSubnets", + + "ec2:DescribeSecurityGroups", + + "ec2:DescribeInstances", + + "ec2:DescribeNetworkInterfaces", + + "ec2:DescribeTags", + + "ec2:GetCoipPoolUsage", + + "ec2:DescribeCoipPools", + + "elasticloadbalancing:DescribeLoadBalancers", + + "elasticloadbalancing:DescribeLoadBalancerAttributes", + + "elasticloadbalancing:DescribeListeners", + + "elasticloadbalancing:DescribeListenerCertificates", + + "elasticloadbalancing:DescribeSSLPolicies", + + "elasticloadbalancing:DescribeRules", + + "elasticloadbalancing:DescribeTargetGroups", + + "elasticloadbalancing:DescribeTargetGroupAttributes", + + "elasticloadbalancing:DescribeTargetHealth", + + "elasticloadbalancing:DescribeTags", + ] + + Effect = "Allow" + + Resource = "*" + }, + + { + + Action = [ + + "cognito-idp:DescribeUserPoolClient", + + "acm:ListCertificates", + + "acm:DescribeCertificate", + + "iam:ListServerCertificates", + + "iam:GetServerCertificate", + + "waf-regional:GetWebACL", + + "waf-regional:GetWebACLForResource", + + "waf-regional:AssociateWebACL", + + "waf-regional:DisassociateWebACL", + + "wafv2:GetWebACL", + + "wafv2:GetWebACLForResource", + + "wafv2:AssociateWebACL", + + "wafv2:DisassociateWebACL", + + "shield:GetSubscriptionState", + + "shield:DescribeProtection", + + "shield:CreateProtection", + + "shield:DeleteProtection", + ] + + Effect = "Allow" + + Resource = "*" + }, + + { + + Action = [ + + "ec2:AuthorizeSecurityGroupIngress", + + "ec2:RevokeSecurityGroupIngress", + ] + + Condition = { + + StringEquals = { + + "aws:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = "*" + }, + + { + + Action = [ + + "ec2:CreateSecurityGroup", + ] + + Effect = "Allow" + + Resource = "*" + }, + + { + + Action = [ + + "ec2:CreateTags", + ] + + Condition = { + + Null = { + + "aws:RequestTag/elbv2.k8s.aws/cluster" = "false" + } + + StringEquals = { + + "ec2:CreateAction" = "CreateSecurityGroup" + } + } + + Effect = "Allow" + + Resource = "arn:aws:ec2:*:*:security-group/*" + }, + + { + + Action = [ + + "ec2:CreateTags", + + "ec2:DeleteTags", + ] + + Condition = { + + Null = { + + "aws:RequestTag/elbv2.k8s.aws/cluster" = "true" + + "aws:ResourceTag/elbv2.k8s.aws/cluster" = "false" + } + } + + Effect = "Allow" + + Resource = "arn:aws:ec2:*:*:security-group/*" + }, + + { + + Action = [ + + "ec2:AuthorizeSecurityGroupIngress", + + "ec2:RevokeSecurityGroupIngress", + + "ec2:DeleteSecurityGroup", + ] + + Condition = { + + Null = { + + "aws:ResourceTag/elbv2.k8s.aws/cluster" = "false" + } + + StringEquals = { + + "aws:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = "*" + }, + + { + + Action = [ + + "elasticloadbalancing:CreateLoadBalancer", + + "elasticloadbalancing:CreateTargetGroup", + ] + + Condition = { + + Null = { + + "aws:RequestTag/elbv2.k8s.aws/cluster" = "false" + } + } + + Effect = "Allow" + + Resource = "*" + }, + + { + + Action = [ + + "elasticloadbalancing:CreateListener", + + "elasticloadbalancing:DeleteListener", + + "elasticloadbalancing:CreateRule", + + "elasticloadbalancing:DeleteRule", + ] + + Effect = "Allow" + + Resource = "*" + }, + + { + + Action = [ + + "elasticloadbalancing:AddTags", + + "elasticloadbalancing:RemoveTags", + ] + + Condition = { + + Null = { + + "aws:RequestTag/elbv2.k8s.aws/cluster" = "true" + + "aws:ResourceTag/elbv2.k8s.aws/cluster" = "false" + } + } + + Effect = "Allow" + + Resource = [ + + "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", + + "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", + + "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*", + ] + }, + + { + + Action = [ + + "elasticloadbalancing:AddTags", + + "elasticloadbalancing:RemoveTags", + ] + + Effect = "Allow" + + Resource = [ + + "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*", + + "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", + + "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*", + + "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*", + ] + }, + + { + + Action = [ + + "elasticloadbalancing:ModifyLoadBalancerAttributes", + + "elasticloadbalancing:SetIpAddressType", + + "elasticloadbalancing:SetSecurityGroups", + + "elasticloadbalancing:SetSubnets", + + "elasticloadbalancing:DeleteLoadBalancer", + + "elasticloadbalancing:ModifyTargetGroup", + + "elasticloadbalancing:ModifyTargetGroupAttributes", + + "elasticloadbalancing:DeleteTargetGroup", + ] + + Condition = { + + Null = { + + "aws:ResourceTag/elbv2.k8s.aws/cluster" = "false" + } + } + + Effect = "Allow" + + Resource = "*" + }, + + { + + Action = [ + + "elasticloadbalancing:RegisterTargets", + + "elasticloadbalancing:DeregisterTargets", + ] + + Effect = "Allow" + + Resource = "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" + }, + + { + + Action = [ + + "elasticloadbalancing:SetWebAcl", + + "elasticloadbalancing:ModifyListener", + + "elasticloadbalancing:AddListenerCertificates", + + "elasticloadbalancing:RemoveListenerCertificates", + + "elasticloadbalancing:ModifyRule", + ] + + Effect = "Allow" + + Resource = "*" + }, + ] + + Version = "2012-10-17" + } + ) + + policy_id = (known after apply) + + tags = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + + tags_all = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + } + + # module.aws-managed-cloud.aws_iam_policy.bootstrap_policy[0] will be created + + resource "aws_iam_policy" "bootstrap_policy" { + + arn = (known after apply) + + description = "This policy sets the minimum amount of permissions needed by the StreamNativeCloudBootstrapRole to bootstrap the StreamNative Cloud deployment." + + id = (known after apply) + + name = "StreamNativeCloudBootstrapPolicy" + + path = "/StreamNative/" + + policy = jsonencode( + { + + Statement = [ + + { + + Action = [ + + "kms:CreateAlias", + + "kms:DeleteAlias", + + "kms:ScheduleKeyDeletion", + + "logs:CreateLogGroup", + + "logs:PutRetentionPolicy", + + "route53:CreateHostedZone", + + "route53:ChangeTagsForResource", + + "support:*", + + "servicequotas:List*", + + "servicequotas:Get*", + ] + + Effect = "Allow" + + Resource = "*" + + Sid = "UnResRW" + }, + + { + + Action = [ + + "acm:ImportCertificate", + + "acm:ListCertificates", + + "acm:ListTagsForCertificate", + + "autoscaling:Describe*", + + "ec2:Describe*", + + "ec2:Get*", + + "eks:Describe*", + + "eks:List*", + + "elasticloadbalancing:Describe*", + + "iam:GetInstanceProfile", + + "iam:GetOpenIDConnectProvider", + + "iam:GetPolicy", + + "iam:GetPolicyVersion", + + "iam:GetRole", + + "iam:List*", + + "kms:DescribeKey", + + "kms:GetKeyPolicy", + + "kms:GetKeyRotationStatus", + + "kms:ListAliases", + + "kms:ListResourceTags", + + "logs:Describe*", + + "logs:List*", + + "route53:Get*", + + "route53:List*", + + "s3:ListAllMyBuckets", + + "s3:ListBucket", + ] + + Effect = "Allow" + + Resource = "*" + + Sid = "RO" + }, + + { + + Action = "iam:AttachRolePolicy" + + Effect = "Allow" + + Resource = "arn:aws:iam::123456789012:role/StreamNative/*" + + Sid = "ResRlPol" + }, + + { + + Action = [ + + "ec2:AuthorizeSecurityGroup*", + + "ec2:RevokeSecurityGroup*", + ] + + Condition = { + + StringEquals = { + + "aws:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = "*" + + Sid = "SecGrpVPC" + }, + + { + + Action = [ + + "ec2:RunInstances", + ] + + Condition = { + + ArnLikeIfExists = { + + "ec2:Vpc" = [ + + "arn:aws:ec2:*:123456789012:vpc/*", + ] + } + } + + Effect = "Allow" + + Resource = "*" + + Sid = "RunInst" + }, + + { + + Action = [ + + "route53:ChangeResourceRecordSets", + ] + + Effect = "Allow" + + Resource = [ + + "arn:aws:route53:::hostedzone/*", + ] + + Sid = "ResR53Z" + }, + + { + + Action = [ + + "eks:DeleteNodeGroup", + ] + + Effect = "Allow" + + Resource = [ + + "arn:aws:eks:*:123456789012:nodegroup/*/*snc*/*", + ] + + Sid = "ResEKS" + }, + + { + + Action = [ + + "autoscaling:*Tags", + + "autoscaling:Delete*", + ] + + Condition = { + + StringLike = { + + "autoscaling:ResourceTag/cluster-name" = "*snc*" + } + } + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "AsgTags" + }, + + { + + Action = [ + + "ec2:Associate*", + + "ec2:Delete*", + + "ec2:Disassociate*", + + "ec2:Modify*", + + "ec2:*TransitGateway*", + ] + + Condition = { + + StringLike = { + + "ec2:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "EC2Tags" + }, + + { + + Action = [ + + "elasticloadbalancing:De*", + + "elasticloadbalancing:*LoadBalancer*", + ] + + Condition = { + + StringLike = { + + "elasticloadbalancing:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "ELBTags" + }, + + { + + Action = [ + + "eks:TagResource", + + "eks:UntagResource", + ] + + Condition = { + + StringLike = { + + "aws:ResourceTag/cluster-name" = "*snc*" + } + } + + Effect = "Allow" + + Resource = "*" + + Sid = "AllowTag" + }, + + { + + Action = [ + + "acm:AddTagsToCertificate", + + "acm:ImportCertificate", + + "acm:RemoveTagsFromCertificate", + + "acm:RequestCertificate", + + "autoscaling:Create*", + + "ec2:*TransitGateway*", + + "ec2:AllocateAddress", + + "ec2:Create*", + + "eks:Create*", + + "eks:RegisterCluster", + + "eks:TagResource", + + "elasticloadbalancing:Add*", + + "kms:CreateKey", + + "kms:TagResource", + ] + + Condition = { + + StringEquals = { + + "aws:RequestTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = "*" + + Sid = "ReqReqTag" + }, + + { + + Action = [ + + "acm:DeleteCertificate", + + "acm:DescribeCertificate", + + "acm:ExportCertificate", + + "acm:GetCertificate", + + "acm:ImportCertificate", + + "acm:RemoveTagsFromCertificate", + + "acm:ResendValidationEmail", + + "autoscaling:AttachInstances", + + "autoscaling:CreateOrUpdateTags", + + "autoscaling:Detach*", + + "autoscaling:Update*", + + "autoscaling:Resume*", + + "autoscaling:Suspend*", + + "autoscaling:SetDesired*", + + "ec2:AssignPrivateIpAddresses", + + "ec2:AttachInternetGateway", + + "ec2:CreateLaunchTemplateVersion", + + "ec2:CreateNatGateway", + + "ec2:CreateNetworkInterface", + + "ec2:CreateRoute", + + "ec2:CreateRouteTable", + + "ec2:CreateSecurityGroup", + + "ec2:CreateSubnet", + + "ec2:CreateTags", + + "ec2:CreateVpcEndpoint", + + "ec2:Detach*", + + "ec2:Release*", + + "ec2:Revoke*", + + "ec2:TerminateInstances", + + "ec2:Update*", + + "eks:DeleteAddon", + + "eks:DeleteCluster", + + "eks:DeleteFargateProfile", + + "eks:DeregisterCluster", + + "eks:U*", + + "elasticloadbalancing:*Listener", + + "elasticloadbalancing:*Rule", + + "elasticloadbalancing:*TargetGroup", + + "elasticloadbalancing:Set*", + + "elasticloadbalancing:Re*", + + "logs:DeleteLogGroup", + + "logs:PutRetentionPolicy", + ] + + Condition = { + + StringEquals = { + + "aws:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = "*" + + Sid = "ReqResrcTag" + }, + + { + + Action = [ + + "s3:CreateBucket", + + "s3:Delete*", + + "s3:Get*", + + "s3:List*", + + "s3:PutBucket*", + + "s3:PutObject*", + + "s3:PutLifecycle*", + + "s3:PutAccelerateConfiguration", + + "s3:PutAccessPointPolicy", + + "s3:PutAccountPublicAccessBlock", + + "s3:PutAnalyticsConfiguration", + + "s3:PutEncryptionConfiguration", + ] + + Effect = "Allow" + + Resource = [ + + "arn:aws:s3:::*snc*", + ] + + Sid = "ResS3" + }, + + { + + Action = [ + + "iam:AddRoleToInstanceProfile", + + "iam:DeleteInstanceProfile", + + "iam:DeleteOpenIDConnectProvider", + + "iam:DeleteRole", + + "iam:DeleteServiceLinkedRole", + + "iam:DetachRolePolicy", + + "iam:PutRolePermissionsBoundary", + + "iam:RemoveRoleFromInstanceProfile", + + "iam:SetDefaultPolicyVersion", + + "iam:UpdateAssumeRolePolicy", + + "iam:UpdateOpenIDConnectProviderThumbprint", + + "iam:UpdateRole", + + "iam:UpdateRoleDescription", + + "iam:Untag*", + + "iam:CreateOpenIDConnectProvider", + + "iam:TagPolicy", + + "iam:TagRole", + + "iam:TagInstanceProfile", + + "iam:TagOpenIDConnectProvider", + + "iam:DeletePolicy", + + "iam:DeletePolicyVersion", + ] + + Condition = { + + StringEquals = { + + "aws:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "arn:aws:iam::123456789012:role/StreamNative/*", + + "arn:aws:iam::123456789012:policy/StreamNative/*", + + "arn:aws:iam::123456789012:oidc-provider/*", + ] + + Sid = "IAMReqTag" + }, + + { + + Action = "iam:CreateServiceLinkedRole" + + Effect = "Allow" + + Resource = "arn:aws:iam::123456789012:role/aws-service-role/*" + + Sid = "SvcLnkRl" + }, + + { + + Action = [ + + "iam:PassRole", + ] + + Condition = { + + StringEquals = { + + "iam:PassedToService" = "eks.amazonaws.com" + } + } + + Effect = "Allow" + + Resource = [ + + "arn:aws:iam::123456789012:role/*snc*", + ] + + Sid = "ResPsRlEKS" + }, + + { + + Action = [ + + "iam:CreateRole", + ] + + Condition = { + + StringEqualsIgnoreCase = { + + "iam:PermissionsBoundary" = "arn:aws:iam:::policy/StreamNative/StreamNativeCloudPermissionBoundary" + } + } + + Effect = "Allow" + + Resource = "arn:aws:iam::123456789012:role/StreamNative/*" + + Sid = "RqPBRls" + }, + ] + + Version = "2012-10-17" + } + ) + + policy_id = (known after apply) + + tags = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + + tags_all = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + } + + # module.aws-managed-cloud.aws_iam_policy.management_role will be created + + resource "aws_iam_policy" "management_role" { + + arn = (known after apply) + + description = "This policy sets the limits for the management role needed for StreamNative's vendor access." + + id = (known after apply) + + name = "StreamNativeCloudManagementPolicy" + + path = "/StreamNative/" + + policy = jsonencode( + { + + Statement = [ + + { + + Action = [ + + "acm:List*", + + "acm:ImportCertificate", + + "cloudwatch:Describe*", + + "cloudwatch:List*", + + "cloudwatch:Get*", + + "logs:Describe*", + + "logs:List*", + + "logs:Filter*", + + "logs:StartQuery", + + "logs:StopQuery", + + "route53:Get*", + + "route53:List*", + + "support:*", + + "servicequotas:List*", + + "servicequotas:Get*", + ] + + Effect = "Allow" + + Resource = "*" + + Sid = "AllowedServices" + }, + + { + + Action = [ + + "autoscaling:Describe*", + ] + + Condition = { + + StringLike = { + + "autoscaling:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "AsgTags" + }, + + { + + Action = [ + + "ec2:Describe*", + + "ec2:Get*", + ] + + Condition = { + + StringLike = { + + "ec2:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "EC2Tags" + }, + + { + + Action = [ + + "elasticloadbalancing:Describe*", + ] + + Condition = { + + StringLike = { + + "elasticloadbalancing:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "ELBTags" + }, + + { + + Action = [ + + "eks:Describe*", + + "eks:List*", + ] + + Condition = { + + StringLike = { + + "eks:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "EKSTags" + }, + + { + + Action = [ + + "iam:GetPolicy*", + + "iam:GetRole*", + + "iam:ListRole*", + + "iam:ListPolic*", + ] + + Effect = "Allow" + + Resource = [ + + "arn:aws:iam::123456789012:role/StreamNative/*", + + "arn:aws:iam::123456789012:policy/StreamNative/*", + + "arn:aws:iam::aws:policy/*", + ] + + Sid = "AllowedIAMReadActions" + }, + + { + + Action = [ + + "iam:CreateRole", + + "iam:TagRole", + ] + + Condition = { + + StringEqualsIgnoreCase = { + + "aws:RequestTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "arn:aws:iam::123456789012:role/StreamNative/*", + ] + + Sid = "IamRequireRequestTag" + }, + + { + + Action = [ + + "iam:AttachRolePolicy", + ] + + Condition = { + + ArnEquals = { + + "iam:PolicyARN" = [ + + "arn:aws:iam::123456789012:policy/StreamNative/StreamNativeCloudManagementPolicy", + ] + } + } + + Effect = "Allow" + + Resource = "arn:aws:iam::123456789012:role/StreamNative/*" + + Sid = "IamAttach" + }, + + { + + Action = [ + + "iam:DeleteRole", + + "iam:DetachRolePolicy", + + "iam:PutRolePermissionsBoundary", + + "iam:SetDefaultPolicyVersion", + + "iam:UpdateAssumeRolePolicy", + + "iam:UpdateRole", + + "iam:UpdateRoleDescription", + ] + + Condition = { + + StringEqualsIgnoreCase = { + + "aws:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "arn:aws:iam::123456789012:role/StreamNative/*", + + "arn:aws:iam::123456789012:policy/StreamNative/*", + ] + + Sid = "IamRequireResourceTag" + }, + + { + + Action = [ + + "acm:DeleteCertificate", + + "acm:DescribeCertificate", + + "acm:GetCertificate", + + "autoscaling:CancelInstanceRefresh", + + "autoscaling:PutScalingPolicy", + + "autoscaling:ResumeProcesses", + + "autoscaling:SetDesiredCapacity", + + "autoscaling:StartInstanceRefresh", + + "autoscaling:SuspendProcesses", + + "autoscaling:UpdateAutoScalingGroup", + + "eks:UpdateNodegroupConfig", + + "eks:UpdateNodegroupVersion", + ] + + Condition = { + + StringEqualsIgnoreCase = { + + "aws:ResourceTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "RequireResourceTag" + }, + + { + + Action = [ + + "acm:AddTagsToCertificate", + + "acm:ImportCertificate", + ] + + Condition = { + + StringEqualsIgnoreCase = { + + "aws:RequestTag/Vendor" = "StreamNative" + } + } + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "RequireRequestTag" + }, + ] + + Version = "2012-10-17" + } + ) + + policy_id = (known after apply) + + tags = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + + tags_all = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + } + + # module.aws-managed-cloud.aws_iam_policy.permission_boundary will be created + + resource "aws_iam_policy" "permission_boundary" { + + arn = (known after apply) + + description = "This policy sets the permission boundary for StreamNative's vendor access. It defines the limits of what StreamNative can do within this AWS account." + + id = (known after apply) + + name = "StreamNativeCloudPermissionBoundary" + + path = "/StreamNative/" + + policy = jsonencode( + { + + Statement = [ + + { + + Action = [ + + "acm:*", + + "autoscaling:*", + + "cognito-idp:*", + + "dynamodb:*", + + "ec2:*", + + "ecr:*", + + "eks:*", + + "elasticloadbalancing:*", + + "iam:GetInstanceProfile", + + "iam:GetOpenIDConnectProvider", + + "iam:GetPolicy", + + "iam:GetPolicyVersion", + + "iam:GetRole", + + "iam:GetServerCertificate", + + "iam:ListAttachedRolePolicies", + + "iam:ListEntitiesForPolicy", + + "iam:ListInstanceProfile*", + + "iam:ListOpenIDConnectProvider*", + + "iam:ListPolicies", + + "iam:ListPolicyTags", + + "iam:ListPolicyVersions", + + "iam:ListRole*", + + "iam:ListServerCertificates", + + "kms:*", + + "logs:*", + + "route53:*", + + "s3:*", + + "servicequotas:*", + + "shield:*", + + "support:*", + + "sts:*", + + "waf-regional:*", + + "wafv2:*", + ] + + Effect = "Allow" + + Resource = "*" + + Sid = "AllowedServices" + }, + + { + + Action = [ + + "iam:AddRoleToInstanceProfile", + + "iam:CreateOpenIDConnectProvider", + + "iam:CreateRole", + + "iam:CreateServiceLinkedRole", + + "iam:DeleteInstanceProfile", + + "iam:DeleteOpenIDConnectProvider", + + "iam:DeletePolicy", + + "iam:DeletePolicyVersion", + + "iam:DeleteRole", + + "iam:DeleteServiceLinkedRole", + + "iam:DetachRolePolicy", + + "iam:PassRole", + + "iam:PutRolePermissionsBoundary", + + "iam:RemoveRoleFromInstanceProfile", + + "iam:SetDefaultPolicyVersion", + + "iam:TagInstanceProfile", + + "iam:TagOpenIDConnectProvider", + + "iam:TagPolicy", + + "iam:TagRole", + + "iam:Untag*", + + "iam:UpdateAssumeRolePolicy", + + "iam:UpdateOpenIDConnectProviderThumbprint", + + "iam:UpdateRole", + + "iam:UpdateRoleDescription", + ] + + Effect = "Allow" + + Resource = [ + + "arn:aws:iam::aws:policy/*", + + "arn:aws:iam::123456789012:role/aws-service-role/*", + + "arn:aws:iam::123456789012:role/*snc*", + + "arn:aws:iam::123456789012:role/StreamNative/*", + + "arn:aws:iam::123456789012:policy/StreamNative/*", + + "arn:aws:iam::123456789012:oidc-provider/*", + + "arn:aws:iam::123456789012:instance-profile/*", + + "arn:aws:iam::123456789012:server-certificate/*", + ] + + Sid = "IamRestrictions" + }, + + { + + Action = [ + + "iam:PassRole", + ] + + Condition = { + + StringEquals = { + + "iam:PassedToService" = "eks.amazonaws.com" + } + } + + Effect = "Allow" + + Resource = "arn:aws:iam::123456789012:role/*snc*" + + Sid = "RestrictPassRoleToEKS" + }, + + { + + Action = [ + + "iam:AttachRolePolicy", + ] + + Condition = { + + "ForAnyValue:ArnLike" = { + + "iam:PolicyARN" = [ + + "arn:aws:iam::123456789012:policy/StreamNative/*", + + "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy", + + "arn:aws:iam::aws:policy/AmazonEKSServicePolicy", + + "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController", + + "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy", + + "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy", + + "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", + + "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy", + ] + } + } + + Effect = "Allow" + + Resource = "arn:aws:iam::123456789012:role/StreamNative/*" + + Sid = "AllowedIAMManagedPolicies" + }, + + { + + Action = [ + + "iam:CreateRole", + ] + + Condition = { + + StringEqualsIgnoreCase = { + + "aws:ResourceTag/Vendor" = "StreamNative" + + "iam:PermissionsBoundary" = "arn:aws:iam:::policy/StreamNative/StreamNativeCloudPermissionBoundary" + } + } + + Effect = "Allow" + + Resource = "arn:aws:iam::123456789012:role/StreamNative/*" + + Sid = "RequirePermissionBoundaryForIamRoles" + }, + + { + + Action = [ + + "iam:Create*", + + "iam:Delete*", + + "iam:Put*", + + "iam:Tag*", + + "iam:Untag*", + + "iam:Update*", + + "iam:Set*", + ] + + Effect = "Deny" + + Resource = [ + + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudBootstrapPolicy", + + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudLBPolicy", + + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudManagementPolicy", + + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudPermissionBoundary", + + "arn:aws:iam:::policy/StreamNative/StreamNativeCloudRuntimePolicy", + + "arn:aws:iam::123456789012:role/StreamNative/StreamNativeBootstrapRole", + + "arn:aws:iam::123456789012:role/StreamNative/StreamNativeManagementRole", + ] + + Sid = "RestrictChangesToVendorAccess" + }, + ] + + Version = "2012-10-17" + } + ) + + policy_id = (known after apply) + + tags = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + + tags_all = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + } + + # module.aws-managed-cloud.aws_iam_policy.runtime_policy will be created + + resource "aws_iam_policy" "runtime_policy" { + + arn = (known after apply) + + description = "This policy defines almost all used by StreamNative cluster components" + + id = (known after apply) + + name = "StreamNativeCloudRuntimePolicy" + + path = "/StreamNative/" + + policy = jsonencode( + { + + Statement = [ + + { + + Action = [ + + "secretsmanager:ListSecrets", + + "route53:ListTagsForResource", + + "route53:ListResourceRecordSets", + + "route53:ListHostedZones*", + + "route53:GetChange", + + "ec2:DescribeVolumesModifications", + + "ec2:DescribeVolumes", + + "ec2:DescribeTags", + + "ec2:DescribeSnapshots", + + "autoscaling:Describe*", + ] + + Effect = "Allow" + + Resource = [ + + "*", + ] + + Sid = "ro" + }, + + { + + Action = "route53:ChangeResourceRecordSets" + + Effect = "Allow" + + Resource = [ + + "arn:aws:route53:::hostedzone/*", + ] + + Sid = "r53sc" + }, + + { + + Action = [ + + "autoscaling:UpdateAutoScalingGroup", + + "autoscaling:TerminateInstanceInAutoScalingGroup", + + "autoscaling:SetDesiredCapacity", + ] + + Condition = { + + StringLike = { + + "autoscaling:ResourceTag/eks:cluster-name" = "*snc*" + } + } + + Effect = "Allow" + + Resource = "*" + + Sid = "asg" + }, + + { + + Action = [ + + "kms:RevokeGrant", + + "kms:ListGrants", + + "kms:CreateGrant", + ] + + Condition = { + + Bool = { + + "kms:GrantIsForAWSResource" = [ + + "true", + ] + } + } + + Effect = "Allow" + + Resource = [ + + "arn:aws:kms:us-west-2:123456789012:key/7f6c7a67-5c0a-4be4-8c87-047288a9c37b", + + "arn:aws:kms:us-west-2:123456789012:key/a2b08e48-ba16-48b0-ad72-8dfc38198d75", + ] + + Sid = "csik1" + }, + + { + + Action = [ + + "kms:ReEncrypt*", + + "kms:GenerateDataKey*", + + "kms:Encrypt", + + "kms:DescribeKey", + + "kms:Decrypt", + ] + + Effect = "Allow" + + Resource = [ + + "arn:aws:kms:us-west-2:123456789012:key/7f6c7a67-5c0a-4be4-8c87-047288a9c37b", + + "arn:aws:kms:us-west-2:123456789012:key/a2b08e48-ba16-48b0-ad72-8dfc38198d75", + ] + + Sid = "csik2" + }, + + { + + Action = [ + + "s3:ListMultipart*", + + "s3:ListBucket", + ] + + Effect = "Allow" + + Resource = "arn:aws:s3:::*snc*" + + Sid = "s3b" + }, + + { + + Action = [ + + "s3:Put*", + + "s3:List*", + + "s3:*Object", + + "s3:*Multipart*", + ] + + Effect = "Allow" + + Resource = "arn:aws:s3:::*snc*" + + Sid = "s3o" + }, + + { + + Action = [ + + "ec2:CreateVolume", + + "ec2:CreateSnapshot", + ] + + Condition = { + + StringLike = { + + "aws:RequestTag/kubernetes.io/cluster/*snc*" = [ + + "owned", + ] + } + } + + Effect = "Allow" + + Resource = "*" + + Sid = "vbc" + }, + + { + + Action = "ec2:CreateTags" + + Condition = { + + StringEquals = { + + "ec2:CreateAction" = [ + + "CreateVolume", + + "CreateSnapshot", + ] + } + } + + Effect = "Allow" + + Resource = [ + + "arn:aws:ec2:*:*:volume/*", + + "arn:aws:ec2:*:*:snapshot/*", + ] + + Sid = "vbt" + }, + + { + + Action = "ec2:DeleteSnapshot" + + Condition = { + + StringLike = { + + "aws:ResourceTag/kubernetes.io/cluster/*snc*" = [ + + "owned", + ] + } + } + + Effect = "Allow" + + Resource = "*" + + Sid = "vbd" + }, + ] + + Version = "2012-10-17" + } + ) + + policy_id = (known after apply) + + tags = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + + tags_all = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + } + + # module.aws-managed-cloud.aws_iam_role.bootstrap_role[0] will be created + + resource "aws_iam_role" "bootstrap_role" { + + arn = (known after apply) + + assume_role_policy = jsonencode( + { + + Statement = [ + + { + + Action = "sts:AssumeRole" + + Effect = "Allow" + + Principal = { + + AWS = "arn:aws:iam::311022431024:role/cloud-manager" + } + + Sid = "" + }, + ] + + Version = "2012-10-17" + } + ) + + create_date = (known after apply) + + description = "This role is used to bootstrap the StreamNative Cloud within the AWS account. It is limited in scope to the attached policy and also the permission boundary." + + force_detach_policies = false + + id = (known after apply) + + managed_policy_arns = (known after apply) + + max_session_duration = 3600 + + name = "StreamNativeCloudBootstrapRole" + + name_prefix = (known after apply) + + path = "/StreamNative/" + + permissions_boundary = (known after apply) + + tags = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + + tags_all = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + + unique_id = (known after apply) + + + inline_policy { + + name = (known after apply) + + policy = (known after apply) + } + } + + # module.aws-managed-cloud.aws_iam_role.management_role will be created + + resource "aws_iam_role" "management_role" { + + arn = (known after apply) + + assume_role_policy = jsonencode( + { + + Statement = [ + + { + + Action = "sts:AssumeRole" + + Condition = { + + StringEquals = { + + "sts:ExternalId" = "*" + } + } + + Effect = "Allow" + + Principal = { + + AWS = "arn:aws:iam::311022431024:role/cloud-manager" + } + + Sid = "AllowStreamNativeVendorAccess" + }, + + { + + Action = "sts:AssumeRoleWithWebIdentity" + + Condition = { + + StringEquals = { + + "accounts.google.com:aud" = "108050666045451143798" + } + } + + Effect = "Allow" + + Principal = { + + Federated = "accounts.google.com" + } + + Sid = "AllowStreamNativeControlPlaneAccess" + }, + ] + + Version = "2012-10-17" + } + ) + + create_date = (known after apply) + + description = "This role is used by StreamNative for the day to day management of the StreamNative Cloud deployment." + + force_detach_policies = false + + id = (known after apply) + + managed_policy_arns = (known after apply) + + max_session_duration = 3600 + + name = "StreamNativeCloudManagementRole" + + name_prefix = (known after apply) + + path = "/StreamNative/" + + permissions_boundary = (known after apply) + + tags = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + + tags_all = { + + "SNVersion" = "3.0.0" + + "Vendor" = "StreamNative" + } + + unique_id = (known after apply) + + + inline_policy { + + name = (known after apply) + + policy = (known after apply) + } + } + + # module.aws-managed-cloud.aws_iam_role_policy_attachment.bootstrap_policy[0] will be created + + resource "aws_iam_role_policy_attachment" "bootstrap_policy" { + + id = (known after apply) + + policy_arn = (known after apply) + + role = "StreamNativeCloudBootstrapRole" + } + + # module.aws-managed-cloud.aws_iam_role_policy_attachment.management_role will be created + + resource "aws_iam_role_policy_attachment" "management_role" { + + id = (known after apply) + + policy_arn = (known after apply) + + role = "StreamNativeCloudManagementRole" + } + +Plan: 9 to add, 0 to change, 0 to destroy. +``` +

+ +3. `terraform apply` + +
(example output)

+ +```bash +$ terraform apply + +Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: yes + +module.aws-managed-cloud.aws_iam_policy.management_role: Creating... +module.aws-managed-cloud.aws_iam_policy.permission_boundary: Creating... +module.aws-managed-cloud.aws_iam_policy.runtime_policy: Creating... +module.aws-managed-cloud.aws_iam_policy.bootstrap_policy[0]: Creating... +module.aws-managed-cloud.aws_iam_policy.alb_policy: Creating... +module.aws-managed-cloud.aws_iam_policy.permission_boundary: Creation complete after 1s [id=arn:aws:iam::123456789012:policy/StreamNative/StreamNativeCloudPermissionBoundary] +module.aws-managed-cloud.aws_iam_policy.management_role: Creation complete after 1s [id=arn:aws:iam::123456789012:policy/StreamNative/StreamNativeCloudManagementPolicy] +module.aws-managed-cloud.aws_iam_policy.runtime_policy: Creation complete after 1s [id=arn:aws:iam::123456789012:policy/StreamNative/StreamNativeCloudRuntimePolicy] +module.aws-managed-cloud.aws_iam_role.bootstrap_role[0]: Creating... +module.aws-managed-cloud.aws_iam_role.management_role: Creating... +module.aws-managed-cloud.aws_iam_policy.bootstrap_policy[0]: Creation complete after 1s [id=arn:aws:iam::123456789012:policy/StreamNative/StreamNativeCloudBootstrapPolicy] +module.aws-managed-cloud.aws_iam_policy.alb_policy: Creation complete after 1s [id=arn:aws:iam::123456789012:policy/StreamNative/StreamNativeCloudLBPolicy] +module.aws-managed-cloud.aws_iam_role.bootstrap_role[0]: Creation complete after 1s [id=StreamNativeCloudBootstrapRole] +module.aws-managed-cloud.aws_iam_role.management_role: Creation complete after 1s [id=StreamNativeCloudManagementRole] +module.aws-managed-cloud.aws_iam_role_policy_attachment.bootstrap_policy[0]: Creating... +module.aws-managed-cloud.aws_iam_role_policy_attachment.management_role: Creating... +module.aws-managed-cloud.aws_iam_role_policy_attachment.management_role: Creation complete after 0s [id=StreamNativeCloudManagementRole-20220928205225222500000001] +module.aws-managed-cloud.aws_iam_role_policy_attachment.bootstrap_policy[0]: Creation complete after 0s [id=StreamNativeCloudBootstrapRole-20220928205225225100000002] + +Apply complete! Resources: 9 added, 0 changed, 0 destroyed. +``` +

+ + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >=1.0.0 | +| [aws](#requirement\_aws) | >= 4.32.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 4.32.0 | +| [local](#provider\_local) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_iam_policy.alb_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.bootstrap_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.management_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.permission_boundary](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_policy.runtime_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.bootstrap_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role.management_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.bootstrap_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.management_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [local_file.alb_policy](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [local_file.bootstrap_policy](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [local_file.management_policy](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [local_file.permission_boundary_policy](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [local_file.runtime_policy](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.streamnative_control_plane_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.streamnative_vendor_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_kms_key.ebs_default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_key) | data source | +| [aws_kms_key.s3_default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_key) | 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 | +|------|-------------|------|---------|:--------:| +| [additional\_iam\_policy\_arns](#input\_additional\_iam\_policy\_arns) | Provide a list of additional IAM policy ARNs allowed for use with iam:AttachRolePolicy, defined in the StreamNativePermissionBoundary. | `list(string)` | `[]` | no | +| [create\_bootstrap\_role](#input\_create\_bootstrap\_role) | Whether or not to create the bootstrap role, which is used by StreamNative for the initial deployment of StreamNative Cloud | `string` | `true` | no | +| [ebs\_kms\_key\_arns](#input\_ebs\_kms\_key\_arns) | Sets the list of allowed KMS key ARNs, if not set, uses the default EBS KMS key | `list(any)` | `[]` | no | +| [eks\_cluster\_pattern](#input\_eks\_cluster\_pattern) | Defines the EKS cluster prefix for streamnative clusters. This should normally remain the default value. | `string` | `"*snc*"` | no | +| [eks\_nodepool\_pattern](#input\_eks\_nodepool\_pattern) | Defines the prefix that scopes which node pools StreamNative is allowed to use. This should normally remain the default value. | `string` | `"*snc*"` | no | +| [external\_ids](#input\_external\_ids) | A list of external IDs that correspond to your Organizations within StreamNative Cloud. Used for all STS assume role calls to the IAM roles created by the module. This will be the organization ID in the StreamNative console, e.g. "["o-xhopj"]". | `list(string)` | n/a | yes | +| [hosted\_zone\_allowed\_ids](#input\_hosted\_zone\_allowed\_ids) | Allows for further scoping down policy for allowed hosted zones. The IDs provided are constructed into ARNs | `list(any)` |
[
"*"
]
| no | +| [region](#input\_region) | The AWS region where your instance of StreamNative Cloud is deployed. Defaults to all regions "*" | `string` | `"*"` | no | +| [s3\_bucket\_pattern](#input\_s3\_bucket\_pattern) | Defines the bucket prefix for StreamNative managed buckets (backup and offload). Typically defaults to "snc-*", but should match the bucket created using the tiered storage resources module | `string` | `"*snc*"` | no | +| [s3\_kms\_key\_arns](#input\_s3\_kms\_key\_arns) | List of KMS key ARNs to use for S3 buckets | `list(string)` | `[]` | no | +| [sn\_policy\_version](#input\_sn\_policy\_version) | The value of SNVersion tag | `string` | `"3.0.0"` | no | +| [source\_identities](#input\_source\_identities) | Place an additional constraint on source identity, disabled by default and only to be used if specified by StreamNative | `list(any)` | `[]` | no | +| [source\_identity\_test](#input\_source\_identity\_test) | The test to use for source identity | `string` | `"ForAnyValue:StringLike"` | no | +| [streamnative\_google\_account\_id](#input\_streamnative\_google\_account\_id) | The Google Cloud service account ID used by StreamNative for Control Plane operations | `string` | `"108050666045451143798"` | no | +| [streamnative\_vendor\_access\_role\_arns](#input\_streamnative\_vendor\_access\_role\_arns) | A list of ARNs provided by StreamNative that enable us to work with the Vendor Access Roles created by this module (StreamNativeCloudBootstrapRole, StreamNativeCloudManagementRole). This is how StreamNative is granted access into your AWS account and should typically be the default value unless directed otherwise. | `list(string)` |
[
"arn:aws:iam::311022431024:role/cloud-manager"
]
| no | +| [tags](#input\_tags) | Extra tags to apply to the resources created by this module. | `map(string)` | `{}` | no | +| [vpc\_allowed\_ids](#input\_vpc\_allowed\_ids) | Allows for further scoping down policy for allowed VPC | `list(any)` |
[
"*"
]
| no | +| [write\_policy\_files](#input\_write\_policy\_files) | Write the policy files locally to disk for debugging and validation | `bool` | `false` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [aws\_lbc\_policy\_arn](#output\_aws\_lbc\_policy\_arn) | The ARN of the AWS Load Balancer Controller Policy, if enabled | +| [bootstrap\_role\_arn](#output\_bootstrap\_role\_arn) | The ARN of the Bootstrap role, if enabled | +| [management\_role\_arn](#output\_management\_role\_arn) | The ARN of the Management Role | +| [permission\_boundary\_policy\_arn](#output\_permission\_boundary\_policy\_arn) | The ARN of the Permission Boundary Policy | +| [runtime\_policy\_arn](#output\_runtime\_policy\_arn) | The ARN of the Runtime Policy, if enabled | + diff --git a/modules/aws/files/aws_lb_controller_iam_policy.json.tpl b/modules/aws/files/aws_lb_controller_iam_policy.json.tpl new file mode 100644 index 0000000..e5c07c1 --- /dev/null +++ b/modules/aws/files/aws_lb_controller_iam_policy.json.tpl @@ -0,0 +1,227 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "iam:CreateServiceLinkedRole" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "iam:AWSServiceName": "elasticloadbalancing.amazonaws.com" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "ec2:DescribeAccountAttributes", + "ec2:DescribeAddresses", + "ec2:DescribeAvailabilityZones", + "ec2:DescribeInternetGateways", + "ec2:DescribeVpcs", + "ec2:DescribeVpcPeeringConnections", + "ec2:DescribeSubnets", + "ec2:DescribeSecurityGroups", + "ec2:DescribeInstances", + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeTags", + "ec2:GetCoipPoolUsage", + "ec2:DescribeCoipPools", + "elasticloadbalancing:DescribeLoadBalancers", + "elasticloadbalancing:DescribeLoadBalancerAttributes", + "elasticloadbalancing:DescribeListeners", + "elasticloadbalancing:DescribeListenerCertificates", + "elasticloadbalancing:DescribeSSLPolicies", + "elasticloadbalancing:DescribeRules", + "elasticloadbalancing:DescribeTargetGroups", + "elasticloadbalancing:DescribeTargetGroupAttributes", + "elasticloadbalancing:DescribeTargetHealth", + "elasticloadbalancing:DescribeTags" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "cognito-idp:DescribeUserPoolClient", + "acm:ListCertificates", + "acm:DescribeCertificate", + "iam:ListServerCertificates", + "iam:GetServerCertificate", + "waf-regional:GetWebACL", + "waf-regional:GetWebACLForResource", + "waf-regional:AssociateWebACL", + "waf-regional:DisassociateWebACL", + "wafv2:GetWebACL", + "wafv2:GetWebACLForResource", + "wafv2:AssociateWebACL", + "wafv2:DisassociateWebACL", + "shield:GetSubscriptionState", + "shield:DescribeProtection", + "shield:CreateProtection", + "shield:DeleteProtection" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:RevokeSecurityGroupIngress" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateSecurityGroup" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateTags" + ], + "Resource": "arn:${partition}:ec2:*:*:security-group/*", + "Condition": { + "StringEquals": { + "ec2:CreateAction": "CreateSecurityGroup" + }, + "Null": { + "aws:RequestTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "ec2:CreateTags", + "ec2:DeleteTags" + ], + "Resource": "arn:${partition}:ec2:*:*:security-group/*", + "Condition": { + "Null": { + "aws:RequestTag/elbv2.k8s.aws/cluster": "true", + "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroupIngress", + "ec2:RevokeSecurityGroupIngress", + "ec2:DeleteSecurityGroup" + ], + "Resource": "*", + "Condition": { + "Null": { + "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" + }, + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:CreateLoadBalancer", + "elasticloadbalancing:CreateTargetGroup" + ], + "Resource": "*", + "Condition": { + "Null": { + "aws:RequestTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:CreateListener", + "elasticloadbalancing:DeleteListener", + "elasticloadbalancing:CreateRule", + "elasticloadbalancing:DeleteRule" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:AddTags", + "elasticloadbalancing:RemoveTags" + ], + "Resource": [ + "arn:${partition}:elasticloadbalancing:*:*:targetgroup/*/*", + "arn:${partition}:elasticloadbalancing:*:*:loadbalancer/net/*/*", + "arn:${partition}:elasticloadbalancing:*:*:loadbalancer/app/*/*" + ], + "Condition": { + "Null": { + "aws:RequestTag/elbv2.k8s.aws/cluster": "true", + "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:AddTags", + "elasticloadbalancing:RemoveTags" + ], + "Resource": [ + "arn:${partition}:elasticloadbalancing:*:*:listener/net/*/*/*", + "arn:${partition}:elasticloadbalancing:*:*:listener/app/*/*/*", + "arn:${partition}:elasticloadbalancing:*:*:listener-rule/net/*/*/*", + "arn:${partition}:elasticloadbalancing:*:*:listener-rule/app/*/*/*" + ] + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:ModifyLoadBalancerAttributes", + "elasticloadbalancing:SetIpAddressType", + "elasticloadbalancing:SetSecurityGroups", + "elasticloadbalancing:SetSubnets", + "elasticloadbalancing:DeleteLoadBalancer", + "elasticloadbalancing:ModifyTargetGroup", + "elasticloadbalancing:ModifyTargetGroupAttributes", + "elasticloadbalancing:DeleteTargetGroup" + ], + "Resource": "*", + "Condition": { + "Null": { + "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" + } + } + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:RegisterTargets", + "elasticloadbalancing:DeregisterTargets" + ], + "Resource": "arn:${partition}:elasticloadbalancing:*:*:targetgroup/*/*" + }, + { + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:SetWebAcl", + "elasticloadbalancing:ModifyListener", + "elasticloadbalancing:AddListenerCertificates", + "elasticloadbalancing:RemoveListenerCertificates", + "elasticloadbalancing:ModifyRule" + ], + "Resource": "*" + } + ] +} diff --git a/modules/aws/files/bootstrap_role_iam_policy.json.tpl b/modules/aws/files/bootstrap_role_iam_policy.json.tpl new file mode 100644 index 0000000..6a4dcfb --- /dev/null +++ b/modules/aws/files/bootstrap_role_iam_policy.json.tpl @@ -0,0 +1,326 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "UnResRW", + "Effect": "Allow", + "Action": [ + "kms:CreateAlias", + "kms:DeleteAlias", + "kms:ScheduleKeyDeletion", + "logs:CreateLogGroup", + "logs:PutRetentionPolicy", + "route53:CreateHostedZone", + "route53:ChangeTagsForResource", + "support:*", + "servicequotas:List*", + "servicequotas:Get*" + ], + "Resource": "*" + }, + { + "Sid": "RO", + "Effect": "Allow", + "Action": [ + "acm:ImportCertificate", + "acm:ListCertificates", + "acm:ListTagsForCertificate", + "autoscaling:Describe*", + "ec2:Describe*", + "ec2:Get*", + "eks:Describe*", + "eks:List*", + "elasticloadbalancing:Describe*", + "iam:GetInstanceProfile", + "iam:GetOpenIDConnectProvider", + "iam:GetPolicy", + "iam:GetPolicyVersion", + "iam:GetRole", + "iam:List*", + "kms:DescribeKey", + "kms:GetKeyPolicy", + "kms:GetKeyRotationStatus", + "kms:ListAliases", + "kms:ListResourceTags", + "logs:Describe*", + "logs:List*", + "route53:Get*", + "route53:List*", + "s3:ListAllMyBuckets", + "s3:ListBucket" + ], + "Resource": "*" + }, + { + "Sid": "ResRlPol", + "Effect": "Allow", + "Action": "iam:AttachRolePolicy", + "Resource": "arn:${partition}:iam::${account_id}:role/StreamNative/*" + }, + { + "Sid": "SecGrpVPC", + "Effect": "Allow", + "Action": [ + "ec2:AuthorizeSecurityGroup*", + "ec2:RevokeSecurityGroup*" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "RunInst", + "Effect": "Allow", + "Action": [ + "ec2:RunInstances" + ], + "Resource": "*", + "Condition": { + "ArnLikeIfExists": { + "ec2:Vpc": ${vpc_ids} + } + } + }, + { + "Sid": "ResR53Z", + "Effect": "Allow", + "Action": [ + "route53:ChangeResourceRecordSets" + ], + "Resource": ${r53_zone_arns} + }, + { + "Sid": "ResEKS", + "Effect": "Allow", + "Action": [ + "eks:DeleteNodeGroup" + ], + "Resource": [ + "arn:${partition}:eks:${region}:${account_id}:nodegroup/*/${nodepool_pattern}/*" + ] + }, + { + "Sid": "AsgTags", + "Effect": "Allow", + "Action": [ + "autoscaling:*Tags", + "autoscaling:Delete*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "autoscaling:ResourceTag/cluster-name": "${cluster_pattern}" + } + } + }, + { + "Sid": "EC2Tags", + "Effect": "Allow", + "Action": [ + "ec2:Associate*", + "ec2:Delete*", + "ec2:Disassociate*", + "ec2:Modify*", + "ec2:*TransitGateway*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "ec2:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "ELBTags", + "Effect": "Allow", + "Action": [ + "elasticloadbalancing:De*", + "elasticloadbalancing:*LoadBalancer*" + ], + "Resource": [ "*" ], + "Condition": { + "StringLike": { + "elasticloadbalancing:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "AllowTag", + "Effect": "Allow", + "Action": [ + "eks:TagResource", + "eks:UntagResource" + ], + "Resource": "*", + "Condition": { + "StringLike": { + "aws:ResourceTag/cluster-name": "${cluster_pattern}" + } + } + }, + { + "Sid": "ReqReqTag", + "Effect": "Allow", + "Action": [ + "acm:AddTagsToCertificate", + "acm:ImportCertificate", + "acm:RemoveTagsFromCertificate", + "acm:RequestCertificate", + "autoscaling:Create*", + "ec2:*TransitGateway*", + "ec2:AllocateAddress", + "ec2:Create*", + "eks:Create*", + "eks:RegisterCluster", + "eks:TagResource", + "elasticloadbalancing:Add*", + "kms:CreateKey", + "kms:TagResource" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:RequestTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "ReqResrcTag", + "Effect": "Allow", + "Action": [ + "acm:DeleteCertificate", + "acm:DescribeCertificate", + "acm:ExportCertificate", + "acm:GetCertificate", + "acm:ImportCertificate", + "acm:RemoveTagsFromCertificate", + "acm:ResendValidationEmail", + "autoscaling:AttachInstances", + "autoscaling:CreateOrUpdateTags", + "autoscaling:Detach*", + "autoscaling:Update*", + "autoscaling:Resume*", + "autoscaling:Suspend*", + "autoscaling:SetDesired*", + "ec2:AssignPrivateIpAddresses", + "ec2:AttachInternetGateway", + "ec2:CreateLaunchTemplateVersion", + "ec2:CreateNatGateway", + "ec2:CreateNetworkInterface", + "ec2:CreateRoute", + "ec2:CreateRouteTable", + "ec2:CreateSecurityGroup", + "ec2:CreateSubnet", + "ec2:CreateTags", + "ec2:CreateVpcEndpoint", + "ec2:Detach*", + "ec2:Release*", + "ec2:Revoke*", + "ec2:TerminateInstances", + "ec2:Update*", + "eks:DeleteAddon", + "eks:DeleteCluster", + "eks:DeleteFargateProfile", + "eks:DeregisterCluster", + "eks:U*", + "elasticloadbalancing:*Listener", + "elasticloadbalancing:*Rule", + "elasticloadbalancing:*TargetGroup", + "elasticloadbalancing:Set*", + "elasticloadbalancing:Re*", + "logs:DeleteLogGroup", + "logs:PutRetentionPolicy" + ], + "Resource": "*", + "Condition": { + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "ResS3", + "Effect": "Allow", + "Action":[ + "s3:CreateBucket", + "s3:Delete*", + "s3:Get*", + "s3:List*", + "s3:PutBucket*", + "s3:PutObject*", + "s3:PutLifecycle*", + "s3:PutAccelerateConfiguration", + "s3:PutAccessPointPolicy", + "s3:PutAccountPublicAccessBlock", + "s3:PutAnalyticsConfiguration", + "s3:PutEncryptionConfiguration" + ], + "Resource": [ + "arn:${partition}:s3:::${bucket_pattern}" + ] + }, + { + "Sid": "IAMReqTag", + "Effect": "Allow", + "Action": [ + "iam:AddRoleToInstanceProfile", + "iam:CreateRole", + "iam:DeleteInstanceProfile", + "iam:DeleteOpenIDConnectProvider", + "iam:DeleteRole", + "iam:DeleteServiceLinkedRole", + "iam:DetachRolePolicy", + "iam:PutRolePermissionsBoundary", + "iam:RemoveRoleFromInstanceProfile", + "iam:SetDefaultPolicyVersion", + "iam:UpdateAssumeRolePolicy", + "iam:UpdateOpenIDConnectProviderThumbprint", + "iam:UpdateRole", + "iam:UpdateRoleDescription", + "iam:Untag*", + "iam:CreateOpenIDConnectProvider", + "iam:TagPolicy", + "iam:TagRole", + "iam:TagInstanceProfile", + "iam:TagOpenIDConnectProvider", + "iam:DeletePolicy", + "iam:DeletePolicyVersion" + ], + "Resource": [ + "arn:${partition}:iam::${account_id}:role/StreamNative/*", + "arn:${partition}:iam::${account_id}:policy/StreamNative/*", + "arn:${partition}:iam::${account_id}:oidc-provider/*" + ], + "Condition": { + "StringEquals": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "SvcLnkRl", + "Effect": "Allow", + "Action": "iam:CreateServiceLinkedRole", + "Resource": "arn:${partition}:iam::${account_id}:role/aws-service-role/*" + }, + { + "Sid": "ResPsRlEKS", + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": [ + "arn:${partition}:iam::${account_id}:role/StreamNative/*", + "arn:${partition}:iam::${account_id}:role/${cluster_pattern}" + ], + "Condition": { + "StringEquals": { + "iam:PassedToService": "eks.amazonaws.com" + } + } + } + ] +} diff --git a/modules/aws/files/management_role_iam_policy.json.tpl b/modules/aws/files/management_role_iam_policy.json.tpl new file mode 100644 index 0000000..7321d8c --- /dev/null +++ b/modules/aws/files/management_role_iam_policy.json.tpl @@ -0,0 +1,145 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowedServices", + "Effect": "Allow", + "Action": [ + "acm:List*", + "acm:ImportCertificate", + "autoscaling:Describe*", + "cloudwatch:Describe*", + "cloudwatch:List*", + "cloudwatch:Get*", + "ec2:Describe*", + "ec2:Get*", + "eks:Describe*", + "eks:List*", + "elasticloadbalancing:Describe*", + "logs:Describe*", + "logs:List*", + "logs:Filter*", + "logs:StartQuery", + "logs:StopQuery", + "route53:Get*", + "route53:List*", + "support:*", + "servicequotas:List*", + "servicequotas:Get*" + ], + "Resource": "*" + }, + { + "Sid": "AllowedIAMReadActions", + "Effect": "Allow", + "Action": [ + "iam:GetPolicy*", + "iam:GetRole*", + "iam:ListRole*", + "iam:ListPolic*" + ], + "Resource": [ + "arn:${partition}:iam::${account_id}:role/StreamNative/*", + "arn:${partition}:iam::${account_id}:policy/StreamNative/*", + "arn:${partition}:iam::aws:policy/*" + ] + }, + { + "Sid": "IamRequireRequestTag", + "Effect": "Allow", + "Action": [ + "iam:CreateRole", + "iam:TagPolicy", + "iam:TagRole" + ], + "Resource": [ + "arn:${partition}:iam::${account_id}:role/StreamNative/*", + "arn:${partition}:iam::${account_id}:policy/StreamNative/*" + ], + "Condition": { + "StringEqualsIgnoreCase": { + "aws:RequestTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "IamAttach", + "Effect": "Allow", + "Action": [ + "iam:AttachRolePolicy" + ], + "Resource": "arn:${partition}:iam::${account_id}:role/StreamNative/*", + "Condition": { + "ArnEquals": { + "iam:PolicyARN": [ + "arn:${partition}:iam::${account_id}:policy/StreamNative/StreamNativeCloudRuntimePolicy" + ] + } + } + }, + { + "Sid": "IamRequireResourceTag", + "Effect": "Allow", + "Action": [ + "iam:DeleteRole", + "iam:DetachRolePolicy", + "iam:PutRolePermissionsBoundary", + "iam:SetDefaultPolicyVersion", + "iam:UpdateAssumeRolePolicy", + "iam:UpdateRole", + "iam:UpdateRoleDescription" + ], + "Resource": [ + "arn:${partition}:iam::${account_id}:role/StreamNative/*", + "arn:${partition}:iam::${account_id}:policy/StreamNative/*" + ], + "Condition": { + "StringEqualsIgnoreCase": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "RequireResourceTag", + "Effect": "Allow", + "Action": [ + "acm:DeleteCertificate", + "acm:DescribeCertificate", + "acm:GetCertificate", + "autoscaling:CancelInstanceRefresh", + "autoscaling:PutScalingPolicy", + "autoscaling:ResumeProcesses", + "autoscaling:SetDesiredCapacity", + "autoscaling:StartInstanceRefresh", + "autoscaling:SuspendProcesses", + "autoscaling:UpdateAutoScalingGroup", + "eks:UpdateNodegroupConfig", + "eks:UpdateNodegroupVersion" + ], + "Resource": [ + "*" + ], + "Condition": { + "StringEqualsIgnoreCase": { + "aws:ResourceTag/Vendor": "StreamNative" + } + } + }, + { + "Sid": "RequireRequestTag", + "Effect": "Allow", + "Action": [ + "acm:AddTagsToCertificate", + "acm:ImportCertificate" + ], + "Resource": [ + "*" + ], + "Condition": { + "StringEqualsIgnoreCase": { + "aws:RequestTag/Vendor": "StreamNative" + } + } + } + ] +} diff --git a/modules/aws/files/permission_boundary_iam_policy.json.tpl b/modules/aws/files/permission_boundary_iam_policy.json.tpl new file mode 100644 index 0000000..c35981c --- /dev/null +++ b/modules/aws/files/permission_boundary_iam_policy.json.tpl @@ -0,0 +1,159 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowedServices", + "Effect": "Allow", + "Action": [ + "acm:*", + "autoscaling:*", + "cognito-idp:*", + "dynamodb:*", + "ec2:*", + "ecr:*", + "eks:*", + "elasticloadbalancing:*", + "iam:GetInstanceProfile", + "iam:GetOpenIDConnectProvider", + "iam:GetPolicy", + "iam:GetPolicyVersion", + "iam:GetRole", + "iam:GetServerCertificate", + "iam:ListAttachedRolePolicies", + "iam:ListEntitiesForPolicy", + "iam:ListInstanceProfile*", + "iam:ListOpenIDConnectProvider*", + "iam:ListPolicies", + "iam:ListPolicyTags", + "iam:ListPolicyVersions", + "iam:ListRole*", + "iam:ListServerCertificates", + "kms:*", + "logs:*", + "route53:*", + "s3:*", + "servicequotas:*", + "shield:*", + "support:*", + "sts:*", + "waf-regional:*", + "wafv2:*" + ], + "Resource": "*" + }, + { + "Sid": "IamRestrictions", + "Effect": "Allow", + "Action": [ + "iam:AddRoleToInstanceProfile", + "iam:CreateOpenIDConnectProvider", + "iam:CreateServiceLinkedRole", + "iam:DeleteInstanceProfile", + "iam:DeleteOpenIDConnectProvider", + "iam:DeletePolicy", + "iam:DeletePolicyVersion", + "iam:DeleteRole", + "iam:DeleteServiceLinkedRole", + "iam:DetachRolePolicy", + "iam:PutRolePermissionsBoundary", + "iam:RemoveRoleFromInstanceProfile", + "iam:SetDefaultPolicyVersion", + "iam:TagInstanceProfile", + "iam:TagOpenIDConnectProvider", + "iam:TagPolicy", + "iam:TagRole", + "iam:Untag*", + "iam:UpdateAssumeRolePolicy", + "iam:UpdateOpenIDConnectProviderThumbprint", + "iam:UpdateRole", + "iam:UpdateRoleDescription" + ], + "Resource": [ + "arn:${partition}:iam::aws:policy/*", + "arn:${partition}:iam::${account_id}:role/aws-service-role/*", + "arn:${partition}:iam::${account_id}:role/StreamNative/*", + "arn:${partition}:iam::${account_id}:policy/StreamNative/*", + "arn:${partition}:iam::${account_id}:oidc-provider/*", + "arn:${partition}:iam::${account_id}:instance-profile/*", + "arn:${partition}:iam::${account_id}:server-certificate/*" + ] + }, + { + "Sid": "RestrictPassRoleToEKS", + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": "arn:${partition}:iam::${account_id}:role/${cluster_pattern}", + "Condition": { + "StringEquals": { + "iam:PassedToService": "eks.amazonaws.com" + } + } + }, + { + "Sid": "AllowedIAMManagedPolicies", + "Effect": "Allow", + "Action": [ + "iam:AttachRolePolicy" + ], + "Resource": "arn:${partition}:iam::${account_id}:role/StreamNative/*", + "Condition": { + "ForAnyValue:ArnLike": { + "iam:PolicyARN": [ ${allowed_iam_policies} ] + } + } + }, + { + "Sid": "RequirePermissionBoundaryForIamRoles", + "Effect": "Allow", + "Action": [ + "iam:CreateRole" + ], + "Resource": "arn:${partition}:iam::${account_id}:role/StreamNative/*", + "Condition": { + "StringEquals": { + "iam:PermissionsBoundary": "arn:${partition}:iam::${account_id}:policy/StreamNative/StreamNativeCloudPermissionBoundary" + } + } + }, + { + "Sid": "ResPsRlEKS", + "Effect": "Allow", + "Action": [ + "iam:PassRole" + ], + "Resource": [ + "arn:${partition}:iam::${account_id}:role/${cluster_pattern}", + "arn:${partition}:iam::${account_id}:role/StreamNative/${cluster_pattern}" + ], + "Condition": { + "StringEquals": { + "iam:PassedToService": "eks.amazonaws.com" + } + } + }, + { + "Sid": "RestrictChangesToVendorAccess", + "Effect": "Deny", + "Action": [ + "iam:Create*", + "iam:Delete*", + "iam:Put*", + "iam:Tag*", + "iam:Untag*", + "iam:Update*", + "iam:Set*" + ], + "Resource": [ + "arn:${partition}:iam:::policy/StreamNative/StreamNativeCloudBootstrapPolicy", + "arn:${partition}:iam:::policy/StreamNative/StreamNativeCloudLBPolicy", + "arn:${partition}:iam:::policy/StreamNative/StreamNativeCloudManagementPolicy", + "arn:${partition}:iam:::policy/StreamNative/StreamNativeCloudPermissionBoundary", + "arn:${partition}:iam:::policy/StreamNative/StreamNativeCloudRuntimePolicy", + "arn:${partition}:iam::${account_id}:role/StreamNative/StreamNativeBootstrapRole", + "arn:${partition}:iam::${account_id}:role/StreamNative/StreamNativeManagementRole" + ] + } + ] +} diff --git a/modules/aws/files/runtime_iam_policy.json.tpl b/modules/aws/files/runtime_iam_policy.json.tpl new file mode 100644 index 0000000..96c023e --- /dev/null +++ b/modules/aws/files/runtime_iam_policy.json.tpl @@ -0,0 +1,145 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ro", + "Effect": "Allow", + "Action": [ + "autoscaling:Describe*", + "secretsmanager:ListSecrets", + "route53:ListTagsForResource", + "route53:ListHostedZones*", + "route53:GetChange", + "ec2:DescribeLaunchTemplateVersions", + "ec2:DescribeImages", + "ec2:DescribeInstanceTypes", + "ec2:DescribeVolumes*", + "ec2:DescribeTags", + "ec2:DescribeSnapshots", + "ec2:GetInstanceTypesFromInstanceRequirements", + "eks:DescribeNodegroup", + "autoscaling:Describe*" + ], + "Resource": ["*"] + }, + { + "Sid": "r53sc", + "Effect": "Allow", + "Action": [ + "route53:ChangeResourceRecordSets", + "route53:ListResourceRecordSets" + ], + "Resource": ${r53_zone_arns} + }, + { + "Sid": "asg", + "Effect": "Allow", + "Action": [ + "autoscaling:UpdateAutoScalingGroup", + "autoscaling:TerminateInstanceInAutoScalingGroup", + "autoscaling:SetDesiredCapacity" + ], + "Resource": "*", + "Condition": { + "StringLike": { + "autoscaling:ResourceTag/eks:cluster-name": "${cluster_pattern}" + } + } + }, + { + "Sid": "csik1", + "Effect": "Allow", + "Action": [ + "kms:RevokeGrant", + "kms:ListGrants", + "kms:CreateGrant" + ], + "Resource": [ ${kms_arns} ], + "Condition": { + "Bool": { + "kms:GrantIsForAWSResource": [ + "true" + ] + } + } + }, + { + "Sid": "csik2", + "Effect": "Allow", + "Action": [ + "kms:ReEncrypt*", + "kms:GenerateDataKey*", + "kms:Encrypt", + "kms:DescribeKey", + "kms:Decrypt" + ], + "Resource": [ ${kms_arns} ] + }, + { + "Sid": "s3b", + "Effect": "Allow", + "Action": [ + "s3:ListMultipart*", + "s3:ListBucket" + ], + "Resource": "arn:aws:s3:::${bucket_pattern}" + }, + { + "Sid": "s3o", + "Effect": "Allow", + "Action": [ + "s3:Put*", + "s3:List*", + "s3:*Object", + "s3:*Multipart*" + ], + "Resource": "arn:aws:s3:::${bucket_pattern}" + }, + { + "Sid": "vbc", + "Effect": "Allow", + "Action": [ + "ec2:CreateVolume", + "ec2:CreateSnapshot" + ], + "Resource": "*", + "Condition": { + "StringLike": { + "aws:RequestTag/kubernetes.io/cluster/${cluster_pattern}": [ + "owned" + ] + } + } + }, + { + "Sid": "vbt", + "Effect": "Allow", + "Action": "ec2:CreateTags", + "Resource": [ + "arn:aws:ec2:*:*:volume/*", + "arn:aws:ec2:*:*:snapshot/*" + ], + "Condition": { + "StringEquals": { + "ec2:CreateAction": [ + "CreateVolume", + "CreateSnapshot" + ] + } + } + }, + { + "Sid": "vbd", + "Effect": "Allow", + "Action": "ec2:DeleteSnapshot", + "Resource": "*", + "Condition": { + "StringLike": { + "aws:ResourceTag/kubernetes.io/cluster/${cluster_pattern}": [ + "owned" + ] + } + } + } + ] +} \ No newline at end of file diff --git a/modules/aws/main.tf b/modules/aws/main.tf new file mode 100644 index 0000000..76f845a --- /dev/null +++ b/modules/aws/main.tf @@ -0,0 +1,300 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +data "aws_caller_identity" "current" {} + +data "aws_iam_policy_document" "streamnative_vendor_access" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "AWS" + identifiers = var.streamnative_vendor_access_role_arns + } + } +} + + +data "aws_kms_key" "ebs_default" { + key_id = "alias/aws/ebs" +} + +data "aws_kms_key" "s3_default" { + key_id = "alias/aws/s3" +} + +data "aws_partition" "current" {} + +locals { + account_id = data.aws_caller_identity.current.account_id + additional_iam_policy_arns = distinct(compact(var.additional_iam_policy_arns)) + allowed_iam_policies = join(", ", formatlist("\"%s\"", distinct(concat(local.additional_iam_policy_arns, local.default_allowed_iam_policies)))) + arn_like_vpcs = formatlist("\"arn:%s:ec2:%s:%s:vpc/%s\"", local.aws_partition, var.region, local.account_id, var.vpc_allowed_ids) + arn_like_vpcs_str = format("[%s]", join(",", local.arn_like_vpcs)) + assume_conditions = concat(local.external_id, local.source_identity) + aws_partition = data.aws_partition.current.partition + build_r53_arns = [for i, v in var.hosted_zone_allowed_ids : format("\"arn:%s:route53:::hostedzone/%s\"", local.aws_partition, v)] + ebs_kms_key_arn = length(var.ebs_kms_key_arns) > 0 ? var.ebs_kms_key_arns : [data.aws_kms_key.ebs_default.arn] + external_id = (var.external_id != "" ? [{ test : "StringEquals", variable : "sts:ExternalId", values : [var.external_id] }] : []) + kms_key_arns = join(", ", formatlist("\"%s\"", distinct(concat(local.ebs_kms_key_arn, local.s3_kms_key_arn)))) + r53_zone_arns = format("[%s]", join(",", local.build_r53_arns)) + s3_kms_key_arn = length(var.s3_kms_key_arns) > 0 ? var.s3_kms_key_arns : [data.aws_kms_key.s3_default.arn] + source_identity = (length(var.source_identities) > 0 ? [{ test : var.source_identity_test, variable : "sts:SourceIdentity", values : var.source_identities }] : []) + tag_set = merge({ Vendor = "StreamNative", SNVersion = var.sn_policy_version }, var.tags) + + default_allowed_iam_policies = compact([ + "arn:${local.aws_partition}:iam::${local.account_id}:policy/StreamNative/*", + "arn:${local.aws_partition}:iam::aws:policy/AmazonEKSClusterPolicy", + "arn:${local.aws_partition}:iam::aws:policy/AmazonEKSServicePolicy", + "arn:${local.aws_partition}:iam::aws:policy/AmazonEKSVPCResourceController", + "arn:${local.aws_partition}:iam::aws:policy/AmazonEKSWorkerNodePolicy", + "arn:${local.aws_partition}:iam::aws:policy/AmazonEKS_CNI_Policy", + "arn:${local.aws_partition}:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly", + "arn:${local.aws_partition}:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy" + ]) +} + +###### +#-- Trust Relationship for StreamNative Vendor Access Roles +###### +data "aws_iam_policy_document" "streamnative_control_plane_access" { + statement { + sid = "AllowStreamNativeVendorAccess" + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "AWS" + identifiers = var.streamnative_vendor_access_role_arns + } + dynamic "condition" { + for_each = local.assume_conditions + content { + test = condition.value["test"] + values = condition.value["values"] + variable = condition.value["variable"] + } + } + } + + statement { + sid = "AllowStreamNativeControlPlaneAccess" + effect = "Allow" + actions = ["sts:AssumeRoleWithWebIdentity"] + + principals { + type = "Federated" + identifiers = [ + "accounts.google.com" + ] + } + condition { + test = "StringEquals" + values = [var.streamnative_google_account_id] + variable = "accounts.google.com:aud" + } + } +} + +###### +#-- Create the IAM Permission Boundary used by all StreamNative +#-- IAM Resources. This restricts what type of access we have +#-- within your AWS Account and is applied to all our IAM Roles +###### +resource "aws_iam_policy" "permission_boundary" { + name = "StreamNativeCloudPermissionBoundary" + description = "This policy sets the permission boundary for StreamNative's vendor access. It defines the limits of what StreamNative can do within this AWS account." + path = "/StreamNative/" + policy = templatefile("${path.module}/files/permission_boundary_iam_policy.json.tpl", + { + account_id = local.account_id + allowed_iam_policies = local.allowed_iam_policies + cluster_pattern = var.eks_cluster_pattern + partition = local.aws_partition + region = var.region + }) + tags = local.tag_set +} + +###### +#-- Create the IAM role for bootstraping of the StreamNative Cloud +#-- This role is only needed for the initial StreamNative Cloud +#-- deployment to an AWS account, or when it is being removed. +###### +resource "aws_iam_role" "bootstrap_role" { + count = var.create_bootstrap_role ? 1 : 0 + name = "StreamNativeCloudBootstrapRole" + description = "This role is used to bootstrap the StreamNative Cloud within the AWS account. It is limited in scope to the attached policy and also the permission boundary." + assume_role_policy = data.aws_iam_policy_document.streamnative_vendor_access.json + path = "/StreamNative/" + permissions_boundary = aws_iam_policy.permission_boundary.arn + tags = local.tag_set +} + +resource "aws_iam_policy" "bootstrap_policy" { + count = var.create_bootstrap_role ? 1 : 0 + name = "StreamNativeCloudBootstrapPolicy" + description = "This policy sets the minimum amount of permissions needed by the StreamNativeCloudBootstrapRole to bootstrap the StreamNative Cloud deployment." + path = "/StreamNative/" + policy = templatefile("${path.module}/files/bootstrap_role_iam_policy.json.tpl", + { + account_id = local.account_id + region = var.region + vpc_ids = local.arn_like_vpcs_str + bucket_pattern = var.s3_bucket_pattern + nodepool_pattern = var.eks_nodepool_pattern + cluster_pattern = var.eks_cluster_pattern + partition = local.aws_partition + r53_zone_arns = local.r53_zone_arns + }) + tags = local.tag_set +} + +resource "aws_iam_role_policy_attachment" "bootstrap_policy" { + count = var.create_bootstrap_role ? 1 : 0 + policy_arn = aws_iam_policy.bootstrap_policy[0].arn + role = aws_iam_role.bootstrap_role[0].name +} + +###### +#-- Create the IAM role for the management of the StreamNative Cloud +#-- This role is used by StreamNative for management and troubleshooting +#-- of the managed deployment. +###### +resource "aws_iam_policy" "management_role" { + name = "StreamNativeCloudManagementPolicy" + description = "This policy sets the limits for the management role needed for StreamNative's vendor access." + path = "/StreamNative/" + policy = templatefile("${path.module}/files/management_role_iam_policy.json.tpl", + { + account_id = data.aws_caller_identity.current.account_id + partition = local.aws_partition + region = var.region + }) + tags = local.tag_set +} + +resource "aws_iam_role" "management_role" { + name = "StreamNativeCloudManagementRole" + description = "This role is used by StreamNative for the day to day management of the StreamNative Cloud deployment." + assume_role_policy = data.aws_iam_policy_document.streamnative_control_plane_access.json + path = "/StreamNative/" + permissions_boundary = aws_iam_policy.permission_boundary.arn + tags = local.tag_set +} + +resource "aws_iam_role_policy_attachment" "management_role" { + policy_arn = aws_iam_policy.management_role.arn + role = aws_iam_role.management_role.name +} + +###### +#-- Creates the IAM Policies used by EKS Cluster add-on services +###### +resource "aws_iam_policy" "runtime_policy" { + name = "StreamNativeCloudRuntimePolicy" + description = "This policy defines almost all used by StreamNative cluster components" + path = "/StreamNative/" + policy = templatefile("${path.module}/files/runtime_iam_policy.json.tpl", + { + bucket_pattern = var.s3_bucket_pattern + cluster_pattern = var.eks_cluster_pattern + kms_arns = local.kms_key_arns + r53_zone_arns = local.r53_zone_arns + }) + tags = local.tag_set +} + +resource "aws_iam_policy" "alb_policy" { + name = "StreamNativeCloudLBPolicy" + description = "The AWS policy as defined by https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.1/docs/install/iam_policy.json" + path = "/StreamNative/" + policy = templatefile("${path.module}/files/aws_lb_controller_iam_policy.json.tpl", + { + vpc_ids = local.arn_like_vpcs_str + partition = local.aws_partition + }) + tags = local.tag_set +} + +###### +#-- Write IAM Policies to Local Files +###### +resource "local_file" "alb_policy" { + count = var.write_policy_files ? 1 : 0 + content = templatefile("${path.module}/files/aws_lb_controller_iam_policy.json.tpl", + { + vpc_ids = local.arn_like_vpcs_str + partition = local.aws_partition + }) + filename = "alb_policy.json" +} + +resource "local_file" "bootstrap_policy" { + count = var.write_policy_files ? 1 : 0 + content = templatefile("${path.module}/files/bootstrap_role_iam_policy.json.tpl", + { + account_id = local.account_id + region = var.region + vpc_ids = local.arn_like_vpcs_str + bucket_pattern = var.s3_bucket_pattern + nodepool_pattern = var.eks_nodepool_pattern + cluster_pattern = var.eks_cluster_pattern + partition = local.aws_partition + r53_zone_arns = local.r53_zone_arns + }) + filename = "bootstrap_policy.json" +} + +resource "local_file" "management_policy" { + count = var.write_policy_files ? 1 : 0 + content = templatefile("${path.module}/files/management_role_iam_policy.json.tpl", + { + account_id = data.aws_caller_identity.current.account_id + region = var.region + partition = local.aws_partition + }) + filename = "management_policy.json" +} + +resource "local_file" "runtime_policy" { + count = var.write_policy_files ? 1 : 0 + content = templatefile("${path.module}/files/runtime_iam_policy.json.tpl", + { + bucket_pattern = var.s3_bucket_pattern + cluster_pattern = var.eks_cluster_pattern + kms_arns = local.kms_key_arns + r53_zone_arns = local.r53_zone_arns + }) + filename = "runtime_policy.json" +} + +resource "local_file" "permission_boundary_policy" { + count = var.write_policy_files ? 1 : 0 + content = templatefile("${path.module}/files/permission_boundary_iam_policy.json.tpl", + { + account_id = local.account_id + allowed_iam_policies = local.allowed_iam_policies + cluster_pattern = var.eks_cluster_pattern + partition = local.aws_partition + region = var.region + }) + filename = "permission_boundary_policy.json" +} diff --git a/modules/aws/outputs.tf b/modules/aws/outputs.tf new file mode 100644 index 0000000..ef50a18 --- /dev/null +++ b/modules/aws/outputs.tf @@ -0,0 +1,43 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +output "bootstrap_role_arn" { + value = join("", aws_iam_role.bootstrap_role.*.arn) + description = "The ARN of the Bootstrap role, if enabled" +} + +output "management_role_arn" { + value = aws_iam_role.management_role.arn + description = "The ARN of the Management Role" +} + +output "runtime_policy_arn" { + value = join("", aws_iam_policy.runtime_policy.*.arn) + description = "The ARN of the Runtime Policy, if enabled" +} + +output "aws_lbc_policy_arn" { + value = join("", aws_iam_policy.alb_policy.*.arn) + description = "The ARN of the AWS Load Balancer Controller Policy, if enabled" +} + +output "permission_boundary_policy_arn" { + value = aws_iam_policy.permission_boundary.arn + description = "The ARN of the Permssion Boundary Policy" +} diff --git a/modules/aws/variables.tf b/modules/aws/variables.tf new file mode 100644 index 0000000..54ac974 --- /dev/null +++ b/modules/aws/variables.tf @@ -0,0 +1,126 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +variable "s3_kms_key_arns" { + default = [] + description = "List of KMS key ARNs to use for S3 buckets" + type = list(string) +} + +variable "additional_iam_policy_arns" { + default = [] + description = "Provide a list of additional IAM policy arns allowed for use with iam:AttachRolePolicy, defined in the StreamNativePermissionBoundary." + type = list(string) +} + +variable "create_bootstrap_role" { + default = true + description = "Whether or not to create the bootstrap role, which is used by StreamNative for the initial deployment of the StreamNative Cloud" + type = string + +} + +variable "ebs_kms_key_arns" { + default = [] + description = "Sets the list of allowed kms key arns, if not set, uses the default ebs kms key" + type = list(any) +} + +variable "eks_cluster_pattern" { + default = "*snc*" + description = "Defines the eks clsuter prefix for streamnative clusters. This should normally remain the default value." + type = string +} + +variable "eks_nodepool_pattern" { + default = "*snc*" + description = "Defines the prefix that scopes which node pools are allowed to be used by StreamNative. This should normally remain the default value." + type = string +} + +variable "external_id" { + description = "A external ID that correspond to your Organization within StreamNative Cloud, used for all STS assume role calls to the IAM roles created by the module. This will be the organization ID in the StreamNative console, e.g. \"o-xhopj\"." + type = string +} + +variable "hosted_zone_allowed_ids" { + default = ["*"] + description = "Allows for further scoping down policy for allowed hosted zones. The IDs provided are constructed into ARNs" + type = list(any) +} + +variable "region" { + default = "*" + description = "The AWS region where your instance of StreamNative Cloud is deployed. Defaults to all regions \"*\"" + type = string +} + +variable "s3_bucket_pattern" { + default = "*snc*" + description = "Defines the bucket prefix for streamnative managed buckets (backup and offload). Typically defaults to \"snc-*\", but should match the bucket created using the tiered-storage-resources module" + type = string +} + +variable "sn_policy_version" { + default = "3.0.0" + description = "The value of SNVersion tag" + type = string +} + +variable "source_identities" { + default = [] + description = "Place an additional constraint on source identity, disabled by default and only to be used if specified by StreamNative" + type = list(any) +} + +variable "source_identity_test" { + default = "ForAnyValue:StringLike" + description = "The test to use for source identity" + type = string +} + +variable "streamnative_google_account_id" { + default = "108050666045451143798" + description = "The Google Cloud service account ID used by StreamNative for Control Plane operations" + type = string +} + +variable "streamnative_vendor_access_role_arns" { + default = ["arn:aws:iam::311022431024:role/cloud-manager"] + description = "A list ARNs provided by StreamNative that enable us to work with the Vendor Access Roles created by this module (StreamNativeCloudBootstrapRole, StreamNativeCloudManagementRole). This is how StreamNative is granted access into your AWS account, and should typically be the default value unless directed otherwise." + type = list(string) +} + +variable "tags" { + default = {} + description = "Extra tags to apply to the resources created by this module." + type = map(string) +} + +variable "vpc_allowed_ids" { + default = ["*"] + description = "Allows for further scoping down policy for allowed VPC" + type = list(any) +} + +variable "write_policy_files" { + default = false + description = "Write the policy files locally to disk for debugging and validation" + type = bool +} diff --git a/modules/aws/versions.tf b/modules/aws/versions.tf new file mode 100644 index 0000000..8ff5bf0 --- /dev/null +++ b/modules/aws/versions.tf @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +terraform { + required_version = ">=1.0.0" + + required_providers { + aws = { + version = ">= 4.32.0" + source = "hashicorp/aws" + } + } +} \ No newline at end of file diff --git a/modules/gcp/README.md b/modules/gcp/README.md new file mode 100644 index 0000000..efd3e26 --- /dev/null +++ b/modules/gcp/README.md @@ -0,0 +1,2 @@ +# StreamNative Cloud - Managed GCP Vendor Access +This module is a work in progress. Contact your StreamNative account representative for more information.