diff --git a/terraform/aws-iam/datadog.tf b/terraform/aws-iam/datadog.tf new file mode 100644 index 0000000..df9c04d --- /dev/null +++ b/terraform/aws-iam/datadog.tf @@ -0,0 +1,111 @@ +# Datadog AWS Integration Resources + +resource "aws_iam_policy" "datadog_integration" { + name = "AWSDataDogIntegration" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "autoscaling:Describe*", + "budgets:ViewBudget", + "cloudfront:GetDistributionConfig", + "cloudfront:ListDistributions", + "cloudtrail:DescribeTrails", + "cloudtrail:GetTrailStatus", + "cloudwatch:Describe*", + "cloudwatch:Get*", + "cloudwatch:List*", + "codedeploy:List*", + "codedeploy:BatchGet*", + "directconnect:Describe*", + "dynamodb:List*", + "dynamodb:Describe*", + "ec2:Describe*", + "ec2:Get*", + "ecs:Describe*", + "ecs:List*", + "elasticache:Describe*", + "elasticache:List*", + "elasticfilesystem:DescribeFileSystems", + "elasticfilesystem:DescribeTags", + "elasticloadbalancing:Describe*", + "elasticmapreduce:List*", + "elasticmapreduce:Describe*", + "es:ListTags", + "es:ListDomainNames", + "es:DescribeElasticsearchDomains", + "health:DescribeEvents", + "health:DescribeEventDetails", + "health:DescribeAffectedEntities", + "kinesis:List*", + "kinesis:Describe*", + "lambda:AddPermission", + "lambda:GetPolicy", + "lambda:List*", + "lambda:RemovePermission", + "logs:Get*", + "logs:Describe*", + "logs:FilterLogEvents", + "logs:TestMetricFilter", + "rds:Describe*", + "rds:List*", + "redshift:DescribeClusters", + "redshift:DescribeLoggingStatus", + "route53:List*", + "s3:GetBucketTagging", + "s3:ListAllMyBuckets", + "s3:GetBucketLogging", + "s3:GetBucketLocation", + "s3:GetBucketNotification", + "s3:ListAllMyBuckets", + "s3:PutBucketNotification", + "ses:Get*", + "sns:List*", + "sns:Publish", + "sqs:ListQueues", + "support:*", + "tag:getResources", + "tag:getTagKeys", + "tag:getTagValues", + "apigateway:GET", + "ec2:SearchTransitGatewayRoutes", + "elasticfilesystem:DescribeAccessPoints", + "fsx:DescribeFileSystems", + "states:ListStateMachines", + "apigateway:GET" + ] + Resource = "*" + } + ] + }) +} + +resource "aws_iam_role" "datadog_integration" { + name = "AWSDataDogIntegration" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + AWS = "arn:aws:iam::464622532012:root" + } + Action = "sts:AssumeRole" + Condition = { + StringEquals = { + "sts:ExternalId" = "63ce1985605d40499b0a2a0091d76b0e" + } + } + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "datadog_integration" { + role = aws_iam_role.datadog_integration.name + policy_arn = aws_iam_policy.datadog_integration.arn +} diff --git a/terraform/aws-iam/main.tf b/terraform/aws-iam/main.tf new file mode 100644 index 0000000..af7b62e --- /dev/null +++ b/terraform/aws-iam/main.tf @@ -0,0 +1,2 @@ +# Data source to get current AWS account info +data "aws_caller_identity" "current" {} diff --git a/terraform/aws-iam/outputs.tf b/terraform/aws-iam/outputs.tf new file mode 100644 index 0000000..7fa7bcc --- /dev/null +++ b/terraform/aws-iam/outputs.tf @@ -0,0 +1,13 @@ +output "role_arns" { + description = "ARNs of IAM roles" + value = { + datadog_integration = aws_iam_role.datadog_integration.arn + } +} + +output "policy_arns" { + description = "ARNs of custom IAM policies" + value = { + datadog_integration = aws_iam_policy.datadog_integration.arn + } +} \ No newline at end of file diff --git a/terraform/aws-iam/pypi_policies.tf b/terraform/aws-iam/pypi_policies.tf new file mode 100644 index 0000000..bae860e --- /dev/null +++ b/terraform/aws-iam/pypi_policies.tf @@ -0,0 +1,154 @@ +# PyPI IAM Policies + +# to clean up (?) +# pypi-bandersnatch-mirror - 1031 days ago +# pypi-db-backup-archive - 795 days ago +# PyPIReadOnly - 913 days ago + +# opensearch +resource "aws_iam_policy" "pypi_elasticsearch" { + name = "PyPIElasticSearch" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "VisualEditor0" + Effect = "Allow" + Action = [ + "es:DescribeReservedElasticsearchInstanceOfferings", + "es:ESHttpGet", + "es:ListTags", + "es:DescribeElasticsearchDomainConfig", + "es:GetUpgradeHistory", + "es:DescribeReservedElasticsearchInstances", + "es:ESHttpHead", + "es:ListDomainNames", + "es:DescribeElasticsearchDomain", + "es:GetCompatibleElasticsearchVersions", + "es:GetUpgradeStatus", + "es:DescribeElasticsearchDomains", + "es:ListElasticsearchInstanceTypes", + "es:ListElasticsearchVersions", + "es:DescribeElasticsearchInstanceTypeLimits" + ] + Resource = "*" + }, + { + Sid = "VisualEditor1" + Effect = "Allow" + Action = "es:*" + Resource = "arn:aws:es:us-east-2:220435833635:domain/warehouse-7/production*" + }, + { + Sid = "VisualEditor2" + Effect = "Allow" + Action = "es:*" + Resource = "arn:aws:es:us-east-2:220435833635:domain/warehouse-opensearch/production*" + } + ] + }) +} + +# amazon ses +resource "aws_iam_policy" "pypi_email" { + name = "PyPIEmail" + description = "Allows sending email as pypi.org" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "ses:SendEmail", + "ses:SendRawEmail" + ] + Resource = "arn:aws:ses:us-west-2:220435833635:identity/pypi.org" + }, + { + Effect = "Allow" + Action = [ + "sns:ConfirmSubscription" + ] + Resource = "arn:aws:sns:us-west-2:220435833635:pypi-ses-delivery-events-topic" + } + ] + }) +} + +# pypi files/docs ro - unused 913 days +# resource "aws_iam_policy" "pypi_readonly" { +# name = "PyPIReadOnly" +# description = "PyPI Files/Docs Read-Only Access" +# +# policy = jsonencode({ +# Version = "2012-10-17" +# Statement = [ +# { +# Effect = "Allow" +# Action = [ +# "s3:GetObject", +# "s3:ListBucket" +# ] +# Resource = [ +# "arn:aws:s3:::pypi-docs", +# "arn:aws:s3:::pypi-docs/*", +# "arn:aws:s3:::pypi-files", +# "arn:aws:s3:::pypi-files/*" +# ] +# } +# ] +# }) +# } + +# s3 r/w +resource "aws_iam_policy" "pypi_s3_access" { + name = "PyPIS3Access" + description = "R/W Access to the PyPI S3 Buckets" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = "s3:ListAllMyBuckets" + Resource = "*" + }, + { + Effect = "Allow" + Action = "s3:*" + Resource = [ + "arn:aws:s3:::pypi-docs", + "arn:aws:s3:::pypi-docs/*" + ] + }, + { + Effect = "Allow" + Action = "s3:*" + Resource = [ + "arn:aws:s3:::pypi-files", + "arn:aws:s3:::pypi-files/*", + "arn:aws:s3:::pypi-files-archive", + "arn:aws:s3:::pypi-files-archive/*" + ] + }, + { + Effect = "Deny" + Action = [ + "s3:DeleteBucket", + "s3:DeleteBucketPolicy", + "s3:DeleteBucketWebsite", + "s3:DeleteObject", + "s3:DeleteObjectVersion" + ] + Resource = [ + "arn:aws:s3:::pypi-files", + "arn:aws:s3:::pypi-files/*", + "arn:aws:s3:::pypi-files-archive", + "arn:aws:s3:::pypi-files-archive/*" + ] + } + ] + }) +} diff --git a/terraform/main.tf b/terraform/main.tf index e231b6f..17eef6d 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -284,6 +284,10 @@ module "inspector" { ngwaf_percent_enabled = 100 } +module "aws-iam" { + source = "./aws-iam" +} + output "nameservers" { value = module.dns.nameservers } output "pypi-ses_delivery_topic" { value = module.email.delivery_topic } output "testpypi-ses_delivery_topic" { value = module.testpypi-email.delivery_topic }