cds-snc / url-shortener

An API written in Python that shortens URLs
MIT License
4 stars 1 forks source link

release: infrastructure v1.0.2 #308

Closed patheard closed 1 year ago

patheard commented 1 year ago

Summary

Initial release of the production infrastructure. The hosted zone and ECR were created locally to bootstrap the process.

Related

github-actions[bot] commented 1 year ago

Production: ecr

✅   Terraform Init: success ✅   Terraform Validate: success ✅   Terraform Format: success ✅   Terraform Plan: success ✅   Conftest: success

Plan: 0 to add, 1 to change, 0 to destroy
Show summary | CHANGE | NAME | |--------|--------------------------| | update | `aws_ecr_repository.api` |
Show plan ```terraform Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: # aws_ecr_repository.api will be updated in-place ~ resource "aws_ecr_repository" "api" { id = "url-shortener/api" ~ image_tag_mutability = "MUTABLE" -> "IMMUTABLE" name = "url-shortener/api" tags = { "CostCentre" = "url-shortener-production" "Terraform" = "true" } # (4 unchanged attributes hidden) # (2 unchanged blocks hidden) } Plan: 0 to add, 1 to change, 0 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan.tfplan To perform exactly these actions, run the following command to apply: terraform apply "plan.tfplan" ```
Show Conftest results ```sh 18 tests, 18 passed, 0 warnings, 0 failures, 0 exceptions ```
github-actions[bot] commented 1 year ago

Production: backup_plan

✅   Terraform Init: success ✅   Terraform Validate: success ✅   Terraform Format: success ✅   Terraform Plan: success ✅   Conftest: success

Plan: 5 to add, 0 to change, 0 to destroy
Show summary | CHANGE | NAME | |--------|------------------------------------------| | add | `aws_backup_plan.backup_plan_default` | | | `aws_backup_selection.selection_default` | | | `aws_backup_vault.vault` | | | `aws_backup_vault_policy.vault_policy` | | | `aws_iam_role.role_backup` |
Show plan ```terraform Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_backup_plan.backup_plan_default will be created + resource "aws_backup_plan" "backup_plan_default" { + arn = (known after apply) + id = (known after apply) + name = "backup_plan_default" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + version = (known after apply) + rule { + completion_window = 180 + enable_continuous_backup = false + rule_name = "backup_rule_default" + schedule = "cron(0 12 * * ? *)" + start_window = 60 + target_vault_name = "vault" + lifecycle { + cold_storage_after = 30 + delete_after = 120 } } } # aws_backup_selection.selection_default will be created + resource "aws_backup_selection" "selection_default" { + iam_role_arn = (known after apply) + id = (known after apply) + name = "backup_selection_default" + not_resources = (known after apply) + plan_id = (known after apply) + resources = [ + "arn:aws:dynamodb:ca-central-1:123456789012:table/url_shortener", ] + condition { + string_equals { + key = (known after apply) + value = (known after apply) } + string_like { + key = (known after apply) + value = (known after apply) } + string_not_equals { + key = (known after apply) + value = (known after apply) } + string_not_like { + key = (known after apply) + value = (known after apply) } } + selection_tag { + key = "backup_plan" + type = "STRINGEQUALS" + value = "default" } } # aws_backup_vault.vault will be created + resource "aws_backup_vault" "vault" { + arn = (known after apply) + force_destroy = false + id = (known after apply) + kms_key_arn = (known after apply) + name = "vault" + recovery_points = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # aws_backup_vault_policy.vault_policy will be created + resource "aws_backup_vault_policy" "vault_policy" { + backup_vault_arn = (known after apply) + backup_vault_name = "vault" + id = (known after apply) + policy = (known after apply) } # aws_iam_role.role_backup will be created + resource "aws_iam_role" "role_backup" { + arn = (known after apply) + assume_role_policy = jsonencode( { + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "backup.amazonaws.com" } + Sid = "" }, ] + Version = "2012-10-17" } ) + create_date = (known after apply) + force_detach_policies = false + id = (known after apply) + managed_policy_arns = [ + "arn:aws:iam::aws:policy/AWSBackupServiceRolePolicyForS3Backup", + "arn:aws:iam::aws:policy/AWSBackupServiceRolePolicyForS3Restore", + "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup", + "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores", ] + max_session_duration = 3600 + name = "aws-backup-service-role-ca-central-1" + name_prefix = (known after apply) + path = "/" + role_last_used = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + unique_id = (known after apply) + inline_policy { + name = (known after apply) + policy = (known after apply) } } Plan: 5 to add, 0 to change, 0 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan.tfplan To perform exactly these actions, run the following command to apply: terraform apply "plan.tfplan" ```
Show Conftest results ```sh 18 tests, 18 passed, 0 warnings, 0 failures, 0 exceptions ```
github-actions[bot] commented 1 year ago

Production: dynamodb

✅   Terraform Init: success ✅   Terraform Validate: success ✅   Terraform Format: success ✅   Terraform Plan: success ✅   Conftest: success

Plan: 1 to add, 0 to change, 0 to destroy
Show summary | CHANGE | NAME | |--------|------------------------------------| | add | `aws_dynamodb_table.url_shortener` |
Show plan ```terraform Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_dynamodb_table.url_shortener will be created + resource "aws_dynamodb_table" "url_shortener" { + arn = (known after apply) + billing_mode = "PAY_PER_REQUEST" + hash_key = "key_id" + id = (known after apply) + name = "url_shortener" + read_capacity = (known after apply) + stream_arn = (known after apply) + stream_label = (known after apply) + stream_view_type = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + write_capacity = (known after apply) + attribute { + name = "email" + type = "S" } + attribute { + name = "key_id" + type = "S" } + global_secondary_index { + hash_key = "email" + name = "emailIndex" + non_key_attributes = [] + projection_type = "ALL" } + point_in_time_recovery { + enabled = true } + server_side_encryption { + enabled = true + kms_key_arn = (known after apply) } + ttl { + attribute_name = "ttl" + enabled = true } } Plan: 1 to add, 0 to change, 0 to destroy. Changes to Outputs: + url_shortener_table_arn = (known after apply) + url_shortener_table_name = (known after apply) ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan.tfplan To perform exactly these actions, run the following command to apply: terraform apply "plan.tfplan" Releasing state lock. This may take a few moments... ```
Show Conftest results ```sh 18 tests, 18 passed, 0 warnings, 0 failures, 0 exceptions ```
github-actions[bot] commented 1 year ago

Production: conformance_pack

✅   Terraform Init: success ✅   Terraform Validate: success ✅   Terraform Format: success ✅   Terraform Plan: success ✅   Conftest: success

Plan: 5 to add, 0 to change, 0 to destroy
Show summary | CHANGE | NAME | |--------|----------------------------------------------------------------------------| | add | `module.conformance_pack.aws_config_conformance_pack.cds_conformance_pack` | | | `module.conformance_pack.aws_s3_object.conformace_pack_yaml` | | | `module.conformance_pack.module.s3.aws_s3_bucket.this` | | | `module.conformance_pack.module.s3.aws_s3_bucket_public_access_block.this` | | | `module.conformance_pack.random_uuid.bucket_suffix` |

✂   Warning: plan has been truncated! See the full plan in the logs.

Show plan ```terraform Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # module.conformance_pack.aws_config_conformance_pack.cds_conformance_pack will be created + resource "aws_config_conformance_pack" "cds_conformance_pack" { + arn = (known after apply) + id = (known after apply) + name = "CDS-Conformance-Pack" + template_s3_uri = (known after apply) + input_parameter { + parameter_name = "AccessKeysRotatedParamMaxAccessKeyAge" + parameter_value = "90" } + input_parameter { + parameter_name = "CloudwatchAlarmActionCheckParamAlarmActionRequired" + parameter_value = "true" } + input_parameter { + parameter_name = "CloudwatchAlarmActionCheckParamInsufficientDataActionRequired" + parameter_value = "false" } + input_parameter { + parameter_name = "CloudwatchAlarmActionCheckParamOkActionRequired" + parameter_value = "false" } + input_parameter { + parameter_name = "ElbPredefinedSecurityPolicySslCheckParamPredefinedPolicyName" + parameter_value = "TLS-1-2-2017-01" } + input_parameter { + parameter_name = "IamCustomerPolicyBlockedKmsActionsParamBlockedActionsPatterns" + parameter_value = "kms:*, kms:Decrypt, kms:ReEncrypt*" } + input_parameter { + parameter_name = "IamInlinePolicyBlockedKmsActionsParamBlockedActionsPatterns" + parameter_value = "kms:*, kms:Decrypt, kms:ReEncrypt*" } + input_parameter { + parameter_name = "IamPasswordPolicyParamMaxPasswordAge" + parameter_value = "90" } + input_parameter { + parameter_name = "IamPasswordPolicyParamMinimumPasswordLength" + parameter_value = "14" } + input_parameter { + parameter_name = "IamPasswordPolicyParamPasswordReusePrevention" + parameter_value = "24" } + input_parameter { + parameter_name = "IamPasswordPolicyParamRequireLowercaseCharacters" + parameter_value = "true" } + input_parameter { + parameter_name = "IamPasswordPolicyParamRequireNumbers" + parameter_value = "true" } + input_parameter { + parameter_name = "IamPasswordPolicyParamRequireSymbols" + parameter_value = "true" } + input_parameter { + parameter_name = "IamPasswordPolicyParamRequireUppercaseCharacters" + parameter_value = "true" } + input_parameter { + parameter_name = "IamUserUnusedCredentialsCheckParamMaxCredentialUsageAge" + parameter_value = "90" } + input_parameter { + parameter_name = "InternetGatewayAuthorizedVpcOnlyParamAuthorizedVpcIds" + parameter_value = "url_shortener_vpc_id" } + input_parameter { + parameter_name = "RedshiftClusterConfigurationCheckParamClusterDbEncrypted" + parameter_value = "true" } + input_parameter { + parameter_name = "RedshiftClusterConfigurationCheckParamLoggingEnabled" + parameter_value = "true" } + input_parameter { + parameter_name = "RedshiftClusterMaintenancesettingsCheckParamAllowVersionUpgrade" + parameter_value = "true" } + input_parameter { + parameter_name = "RestrictedIncomingTrafficParamBlockedPort1" + parameter_value = "20" } + input_parameter { + parameter_name = "RestrictedIncomingTrafficParamBlockedPort2" + parameter_value = "21" } + input_parameter { + parameter_name = "RestrictedIncomingTrafficParamBlockedPort3" + parameter_value = "3389" } + input_parameter { + parameter_name = "RestrictedIncomingTrafficParamBlockedPort4" + parameter_value = "3306" } + input_parameter { + parameter_name = "RestrictedIncomingTrafficParamBlockedPort5" + parameter_value = "4333" } + input_parameter { + parameter_name = "VpcSgOpenOnlyToAuthorizedPortsParamAuthorizedTcpPorts" + parameter_value = "443" } } # module.conformance_pack.aws_s3_object.conformace_pack_yaml will be created + resource "aws_s3_object" "conformace_pack_yaml" { + acl = "private" + bucket = (known after apply) + bucket_key_enabled = (known after apply) + content = <<-EOT "Conditions": "accessKeysRotatedParamMaxAccessKeyAge": "Fn::Not": - "Fn::Equals": - "" - "Ref": "AccessKeysRotatedParamMaxAccessKeyAge" "cloudwatchAlarmActionCheckParamAlarmActionRequired": "Fn::Not": - "Fn::Equals": - "" - "Ref": "CloudwatchAlarmActionCheckParamAlarmActionRequired" "cloudwatchAlarmActionCheckParamInsufficientDataActionRequired": "Fn::Not": - "Fn::Equals": - "" - "Ref": "CloudwatchAlarmActionCheckParamInsufficientDataActionRequired" "cloudwatchAlarmActionCheckParamOkActionRequired": "Fn::Not": - "Fn::Equals": - "" - "Ref": "CloudwatchAlarmActionCheckParamOkActionRequired" "elbPredefinedSecurityPolicySslCheckParamPredefinedPolicyName": "Fn::Not": - "Fn::Equals": - "" - "Ref": "ElbPredefinedSecurityPolicySslCheckParamPredefinedPolicyName" "iamCustomerPolicyBlockedKmsActionsParamBlockedActionsPatterns": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamCustomerPolicyBlockedKmsActionsParamBlockedActionsPatterns" "iamInlinePolicyBlockedKmsActionsParamBlockedActionsPatterns": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamInlinePolicyBlockedKmsActionsParamBlockedActionsPatterns" "iamPasswordPolicyParamMaxPasswordAge": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamPasswordPolicyParamMaxPasswordAge" "iamPasswordPolicyParamMinimumPasswordLength": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamPasswordPolicyParamMinimumPasswordLength" "iamPasswordPolicyParamPasswordReusePrevention": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamPasswordPolicyParamPasswordReusePrevention" "iamPasswordPolicyParamRequireLowercaseCharacters": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamPasswordPolicyParamRequireLowercaseCharacters" "iamPasswordPolicyParamRequireNumbers": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamPasswordPolicyParamRequireNumbers" "iamPasswordPolicyParamRequireSymbols": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamPasswordPolicyParamRequireSymbols" "iamPasswordPolicyParamRequireUppercaseCharacters": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamPasswordPolicyParamRequireUppercaseCharacters" "iamUserUnusedCredentialsCheckParamMaxCredentialUsageAge": "Fn::Not": - "Fn::Equals": - "" - "Ref": "IamUserUnusedCredentialsCheckParamMaxCredentialUsageAge" "internetGatewayAuthorizedVpcOnlyParamAuthorizedVpcIds": "Fn::Not": - "Fn::Equals": - "" - "Ref": "InternetGatewayAuthorizedVpcOnlyParamAuthorizedVpcIds" "redshiftClusterConfigurationCheckParamClusterDbEncrypted": "Fn::Not": - "Fn::Equals": - "" - "Ref": "RedshiftClusterConfigurationCheckParamClusterDbEncrypted" "redshiftClusterConfigurationCheckParamLoggingEnabled": "Fn::Not": - "Fn::Equals": - "" - "Ref": "RedshiftClusterConfigurationCheckParamLoggingEnabled" "redshiftClusterMaintenancesettingsCheckParamAllowVersionUpgrade": "Fn::Not": - "Fn::Equals": - "" - "Ref": "RedshiftClusterMaintenancesettingsCheckParamAllowVersionUpgrade" "restrictedIncomingTrafficParamBlockedPort1": "Fn::Not": - "Fn::Equals": - "" - "Ref": "RestrictedIncomingTrafficParamBlockedPort1" "restrictedIncomingTrafficParamBlockedPort2": "Fn::Not": - "Fn::Equals": - "" - "Ref": "RestrictedIncomingTrafficParamBlockedPort2" "restrictedIncomingTrafficParamBlockedPort3": "Fn::Not": - "Fn::Equals": - "" - "Ref": "RestrictedIncomingTrafficParamBlockedPort3" "restrictedIncomingTrafficParamBlockedPort4": "Fn::Not": - "Fn::Equals": - "" - "Ref": "RestrictedIncomingTrafficParamBlockedPort4" "restrictedIncomingTrafficParamBlockedPort5": "Fn::Not": - "Fn::Equals": - "" - "Ref": "RestrictedIncomingTrafficParamBlockedPort5" "vpcSgOpenOnlyToAuthorizedPortsParamAuthorizedTcpPorts": "Fn::Not": - "Fn::Equals": - "" - "Ref": "VpcSgOpenOnlyToAuthorizedPortsParamAuthorizedTcpPorts" "Parameters": "AccessKeysRotatedParamMaxAccessKeyAge": "Default": "90" "Type": "String" "CloudwatchAlarmActionCheckParamAlarmActionRequired": "Default": "true" "Type": "String" "CloudwatchAlarmActionCheckParamInsufficientDataActionRequired": "Default": "true" "Type": "String" "CloudwatchAlarmActionCheckParamOkActionRequired": "Default": "false" "Type": "String" "ElbPredefinedSecurityPolicySslCheckParamPredefinedPolicyName": "Default": "TLS-1-2-2017-01" "Type": "String" "IamCustomerPolicyBlockedKmsActionsParamBlockedActionsPatterns": "Default": "kms:*, kms:Decrypt, kms:ReEncrypt*" "Type": "String" "IamInlinePolicyBlockedKmsActionsParamBlockedActionsPatterns": "Default": "kms:*, kms:Decrypt, kms:ReEncrypt*" "Type": "String" "IamPasswordPolicyParamMaxPasswordAge": "Default": "90" "Type": "String" "IamPasswordPolicyParamMinimumPasswordLength": "Default": "14" "Type": "String" "IamPasswordPolicyParamPasswordReusePrevention": "Default": "24" "Type": "String" "IamPasswordPolicyParamRequireLowercaseCharacters": "Default": "true" "Type": "String" "IamPasswordPolicyParamRequireNumbers": "Default": "true" "Type": "String" "IamPasswordPolicyParamRequireSymbols": "Default": "true" "Type": "String" "IamPasswordPolicyParamRequireUppercaseCharacters": "Default": "true" "Type": "String" "IamUserUnusedCredentialsCheckParamMaxCredentialUsageAge": "Default": "90" "Type": "String" "InternetGatewayAuthorizedVpcOnlyParamAuthorizedVpcIds": "Default": "here add Comma-separated list of the authorized VPC IDs" "Type": "String" "RedshiftClusterConfigurationCheckParamClusterDbEncrypted": "Default": "true" "Type": "String" "RedshiftClusterConfigurationCheckParamLoggingEnabled": "Default": "true" "Type": "String" "RedshiftClusterMaintenancesettingsCheckParamAllowVersionUpgrade": "Default": "true" "Type": "String" "RestrictedIncomingTrafficParamBlockedPort1": "Default": "20" "Type": "String" "RestrictedIncomingTrafficParamBlockedPort2": "Default": "21" "Type": "String" "RestrictedIncomingTrafficParamBlockedPort3": "Default": "3389" "Type": "String" "RestrictedIncomingTrafficParamBlockedPort4": "Default": "3306" "Type": "String" "RestrictedIncomingTrafficParamBlockedPort5": "Default": "4333" "Type": "String" "VpcSgOpenOnlyToAuthorizedPortsParamAuthorizedTcpPorts": "Default": "443" "Type": "String" "Resources": "AccessKeysRotated": "Properties": "ConfigRuleName": "access-keys-rotated" "InputParameters": "maxAccessKeyAge": "Fn::If": - "accessKeysRotatedParamMaxAccessKeyAge" - "Ref": "AccessKeysRotatedParamMaxAccessKeyAge" - "Ref": "AWS::NoValue" "Source": "Owner": "AWS" "SourceIdentifier": "ACCESS_KEYS_ROTATED" "Type": "AWS::Config::ConfigRule" "AlbHttpToHttpsRedirectionCheck": "Properties": "ConfigRuleName": "alb-http-to-https-redirection-check" "Source": "Owner": "AWS" "SourceIdentifier": "ALB_HTTP_TO_HTTPS_REDIRECTION_CHECK" "Type": "AWS::Config::ConfigRule" "AlbWafEnabled": "Properties": "ConfigRuleName": "alb-waf-enabled" "Scope": "ComplianceResourceTypes": - "AWS::ElasticLoadBalancingV2::LoadBalancer" "Source": "Owner": "AWS" "SourceIdentifier": "ALB_WAF_ENABLED" "Type": "AWS::Config::ConfigRule" "ApiGwExecutionLoggingEnabled": "Properties": "ConfigRuleName": "api-gw-execution-logging-enabled" "Scope": "ComplianceResourceTypes": - "AWS::ApiGateway::Stage" - "AWS::ApiGatewayV2::Stage" "Source": "Owner": "AWS" "SourceIdentifier": "API_GW_EXECUTION_LOGGING_ENABLED" "Type": "AWS::Config::ConfigRule" "ApiGwSslEnabled": "Properties": "ConfigRuleName": "api-gw-ssl-enabled" "Scope": "ComplianceResourceTypes": - "AWS::ApiGateway::Stage" "Source": "Owner": "AWS" "SourceIdentifier": "API_GW_SSL_ENABLED" "Type": "AWS::Config::ConfigRule" "ApiGwXrayEnabled": "Properties": "ConfigRuleName": "api-gw-xray-enabled" "Scope": "ComplianceResourceTypes": - "AWS::ApiGateway::Stage" "Source": "Owner": "AWS" "SourceIdentifier": "API_GW_XRAY_ENABLED" "Type": "AWS::Config::ConfigRule" "AuroraResourcesProtectedByBackupPlan": "Properties": "ConfigRuleName": "aurora-resources-protected-by-backup-plan" "Scope": "ComplianceResourceTypes": - "AWS::RDS::DBCluster" "Source": "Owner": "AWS" "SourceIdentifier": "AURORA_RESOURCES_PROTECTED_BY_BACKUP_PLAN" "Type": "AWS::Config::ConfigRule" "AutoscalingGroupElbHealthcheckRequired": "Properties": "ConfigRuleName": "autoscaling-group-elb-healthcheck-required" "Scope": "ComplianceResourceTypes": - "AWS::AutoScaling::AutoScalingGroup" "Source": "Owner": "AWS" "SourceIdentifier": "AUTOSCALING_GROUP_ELB_HEALTHCHECK_REQUIRED" "Type": "AWS::Config::ConfigRule" "BackupPlanMinFrequencyAndMinRetentionCheck": "Properties": "ConfigRuleName": "backup-plan-min-frequency-and-min-retention-check" "Scope": "ComplianceResourceTypes": - "AWS::Backup::BackupPlan" "Source": "Owner": "AWS" "SourceIdentifier": "BACKUP_PLAN_MIN_FREQUENCY_AND_MIN_RETENTION_CHECK" "Type": "AWS::Config::ConfigRule" "BackupRecoveryPointEncrypted": "Properties": "ConfigRuleName": "backup-recovery-point-encrypted" "Scope": "ComplianceResourceTypes": - "AWS::Backup::RecoveryPoint" "Source": "Owner": "AWS" "SourceIdentifier": "BACKUP_RECOVERY_POINT_ENCRYPTED" "Type": "AWS::Config::ConfigRule" "BackupRecoveryPointManualDeletionDisabled": "Properties": "ConfigRuleName": "backup-recovery-point-manual-deletion-disabled" "Scope": "ComplianceResourceTypes": - "AWS::Backup::BackupVault" "Source": "Owner": "AWS" "SourceIdentifier": "BACKUP_RECOVERY_POINT_MANUAL_DELETION_DISABLED" "Type": "AWS::Config::ConfigRule" "BackupRecoveryPointMinimumRetentionCheck": "Properties": "ConfigRuleName": "backup-recovery-point-minimum-retention-check" "Scope": "ComplianceResourceTypes": - "AWS::Backup::RecoveryPoint" "Source": "Owner": "AWS" "SourceIdentifier": "BACKUP_RECOVERY_POINT_MINIMUM_RETENTION_CHECK" "Type": "AWS::Config::ConfigRule" "BeanstalkEnhancedHealthReportingEnabled": "Properties": "ConfigRuleName": "beanstalk-enhanced-health-reporting-enabled" "Scope": "ComplianceResourceTypes": - "AWS::ElasticBeanstalk::Environment" "Source": "Owner": "AWS" "SourceIdentifier": "BEANSTALK_ENHANCED_HEALTH_REPORTING_ENABLED" "Type": "AWS::Config::ConfigRule" "CloudTrailEnabled": "Properties": "ConfigRuleName": "cloudtrail-enabled" "Source": "Owner": "AWS" "SourceIdentifier": "CLOUD_TRAIL_ENABLED" "Type": "AWS::Config::ConfigRule" "CloudTrailLogFileValidationEnabled": "Properties": "ConfigRuleName": "cloud-trail-log-file-validation-enabled" "Source": "Owner": "AWS" "SourceIdentifier": "CLOUD_TRAIL_LOG_FILE_VALIDATION_ENABLED" "Type": "AWS::Config::ConfigRule" "CloudtrailS3DataeventsEnabled": "Properties": "ConfigRuleName": "cloudtrail-s3-dataevents-enabled" "Source": "Owner": "AWS" "SourceIdentifier": "CLOUDTRAIL_S3_DATAEVENTS_ENABLED" "Type": "AWS::Config::ConfigRule" "CloudwatchAlarmActionCheck": "Properties": "ConfigRuleName": "cloudwatch-alarm-action-check" "InputParameters": "alarmActionRequired": "Fn::If": - "cloudwatchAlarmActionCheckParamAlarmActionRequired" - "Ref": "CloudwatchAlarmActionCheckParamAlarmActionRequired" - "Ref": "AWS::NoValue" "insufficientDataActionRequired": "Fn::If": - "cloudwatchAlarmActionCheckParamInsufficientDataActionRequired" - "Ref": "CloudwatchAlarmActionCheckParamInsufficientDataActionRequired" - "Ref": "AWS::NoValue" "okActionRequired": "Fn::If": - "cloudwatchAlarmActionCheckParamOkActionRequired" - "Ref": "CloudwatchAlarmActionCheckParamOkActionRequired" - "Ref": "AWS::NoValue" "Scope": "ComplianceResourceTypes": - "AWS::CloudWatch::Alarm" "Source": "Owner": "AWS" "SourceIdentifier": "CLOUDWATCH_ALARM_ACTION_CHECK" "Type": "AWS::Config::ConfigRule" "CmkBackingKeyRotationEnabled": "Properties": "ConfigRuleName": "cmk-backing-key-rotation-enabled" "Source": "Owner": "AWS" "SourceIdentifier": "CMK_BACKING_KEY_ROTATION_ENABLED" "Type": "AWS::Config::ConfigRule" "CwLoggroupRetentionPeriodCheck": "Properties": "ConfigRuleName": "cw-loggroup-retention-period-check" "Source": "Owner": "AWS" "SourceIdentifier": "CW_LOGGROUP_RETENTION_PERIOD_CHECK" "Type": "AWS::Config::ConfigRule" "DbInstanceBackupEnabled": "Properties": "ConfigRuleName": "db-instance-backup-enabled" "Scope": "ComplianceResourceTypes": - "AWS::RDS::DBInstance" "Source": "Owner": "AWS" "SourceIdentifier": "DB_INSTANCE_BACKUP_ENABLED" "Type": "AWS::Config::ConfigRule" "DmsReplicationNotPublic": "Properties": "ConfigRuleName": "dms-replication-not-public" "Scope": "ComplianceResourceTypes": [] "Source": "Owner": "AWS" "SourceIdentifier": "DMS_REPLICATION_NOT_PUBLIC" "Type": "AWS::Config::ConfigRule" "DynamodbAutoscalingEnabled": "Properties": "ConfigRuleName": "dynamodb-autoscaling-enabled" "Scope": "ComplianceResourceTypes": - "AWS::DynamoDB::Table" "Source": "Owner": "AWS" "SourceIdentifier": "DYNAMODB_AUTOSCALING_ENABLED" "Type": "AWS::Config::ConfigRule" "DynamodbPitrEnabled": "Properties": "ConfigRuleName": "dynamodb-pitr-enabled" "Scope": "ComplianceResourceTypes": - "AWS::DynamoDB::Table" "Source": "Owner": "AWS" "SourceIdentifier": "DYNAMODB_PITR_ENABLED" "Type": "AWS::Config::ConfigRule" "DynamodbResourcesProtectedByBackupPlan": "Properties": "ConfigRuleName": "dynamodb-resources-protected-by-backup-plan" "Scope": "ComplianceResourceTypes": - "AWS::DynamoDB::Table" "Source": "Owner": "AWS" "SourceIdentifier": "DYNAMODB_RESOURCES_PROTECTED_BY_BACKUP_PLAN" "Type": "AWS::Config::ConfigRule" "DynamodbThroughputLimitCheck": "Properties": "ConfigRuleName": "dynamodb-throughput-limit-check" "Source": "Owner": "AWS" "SourceIdentifier": "DYNAMODB_THROUGHPUT_LIMIT_CHECK" "Type": "AWS::Config::ConfigRule" "EbsOptimizedInstance": "Properties": "ConfigRuleName": "ebs-optimized-instance" "Scope": "ComplianceResourceTypes": - "AWS::EC2::Instance" "Source": "Owner": "AWS" "SourceIdentifier": "EBS_OPTIMIZED_INSTANCE" "Type": "AWS::Config::ConfigRule" "EbsResourcesProtectedByBackupPlan": "Properties": "ConfigRuleName": "ebs-resources-protected-by-backup-plan" "Scope": "ComplianceResourceTypes": - "AWS::EC2::Volume" "Source": "Owner": "AWS" "SourceIdentifier": "EBS_RESOURCES_PROTECTED_BY_BACKUP_PLAN" "Type": "AWS::Config::ConfigRule" "EbsSnapshotPublicRestorableCheck": "Properties": "ConfigRuleName": "ebs-snapshot-public-restorable-check" "Source": "Owner": "AWS" "SourceIdentifier": "EBS_SNAPSHOT_PUBLIC_RESTORABLE_CHECK" "Type": "AWS::Config::ConfigRule" "Ec2EbsEncryptionByDefault": "Properties": "ConfigRuleName": "ec2-ebs-encryption-by-default" "Source": "Owner": "AWS" "SourceIdentifier": "EC2_EBS_ENCRYPTION_BY_DEFAULT" "Type": "AWS::Config::ConfigRule" "Ec2Imdsv2Check": "Properties": "ConfigRuleName": "ec2-imdsv2-check" "Scope": "ComplianceResourceTypes": - "AWS::EC2::Instance" "Source": "Owner": "AWS" "SourceIdentifier": "EC2_IMDSV2_CHECK" "Type": "AWS::Config::ConfigRule" "Ec2InstanceDetailedMonitoringEnabled": "Properties": "ConfigRuleName": "ec2-instance-detailed-monitoring-enabled" "Scope": "ComplianceResourceTypes": - "AWS::EC2::Instance" "Source": "Owner": "AWS" "SourceIdentifier": "EC2_INSTANCE_DETAILED_MONITORING_ENABLED" "Type": "AWS::Config::ConfigRule" "Ec2InstanceManagedBySsm": "Properties": "ConfigRuleName": "ec2-instance-managed-by-systems-manager" "Scope": "ComplianceResourceTypes": - "AWS::EC2::Instance" - "AWS::SSM::ManagedInstanceInventory" "Source": "Owner": "AWS" "SourceIdentifier": "EC2_INSTANCE_MANAGED_BY_SSM" "Type": "AWS::Config::ConfigRule" "Ec2InstanceNoPublicIp": "Properties": "ConfigRuleName": "ec2-instance-no-public-ip" "Scope": "ComplianceResourceTypes": - "AWS::EC2::Instance" "Source": "Owner": "AWS" "SourceIdentifier": "EC2_INSTANCE_NO_PUBLIC_IP" "Type": "AWS::Config::ConfigRule" "Ec2ManagedinstanceAssociationComplianceStatusCheck": "Properties": "ConfigRuleName": "ec2-managedinstance-association-compliance-status-check" "Scope": "ComplianceResourceTypes": - "AWS::SSM::AssociationCompliance" "Source": "Owner": "AWS" "SourceIdentifier": "EC2_MANAGEDINSTANCE_ASSOCIATION_COMPLIANCE_STATUS_CHECK" "Type": "AWS::Config::ConfigRule" "Ec2ManagedinstancePatchComplianceStatusCheck": "Properties": "ConfigRuleName": "ec2-managedinstance-patch-compliance-status-check" "Scope": "ComplianceResourceTypes": - "AWS::SSM::PatchCompliance" "Source": "Owner": "AWS" "SourceIdentifier": "EC2_MANAGEDINSTANCE_PATCH_COMPLIANCE_STATUS_CHECK" "Type":... ```
Show Conftest results ```sh WARN - plan.json - main - Missing Common Tags: ["module.conformance_pack.aws_s3_object.conformace_pack_yaml"] 18 tests, 17 passed, 1 warning, 0 failures, 0 exceptions ```
github-actions[bot] commented 1 year ago

Production: network

✅   Terraform Init: success ✅   Terraform Validate: success ✅   Terraform Format: success ✅   Terraform Plan: success ✅   Conftest: success

Plan: 57 to add, 0 to change, 0 to destroy
Show summary | CHANGE | NAME | |--------|--------------------------------------------------------------------------------------------------------| | add | `aws_flow_log.cloud_based_sensor` | | | `aws_security_group.api` | | | `aws_security_group.vpc_endpoint` | | | `aws_security_group_rule.api_egress_internet` | | | `aws_security_group_rule.s3_private_endpoint_ingress` | | | `aws_security_group_rule.vpc_endpoint_dynamodb_ingress` | | | `aws_security_group_rule.vpc_endpoint_interface_ingress` | | | `aws_vpc_endpoint.dynamodb` | | | `aws_vpc_endpoint.logs` | | | `aws_vpc_endpoint.s3` | | | `module.url_shortener_vpc.aws_cloudwatch_log_group.flow_logs[0]` | | | `module.url_shortener_vpc.aws_default_network_acl.default` | | | `module.url_shortener_vpc.aws_default_route_table.default` | | | `module.url_shortener_vpc.aws_default_security_group.default` | | | `module.url_shortener_vpc.aws_eip.nat[0]` | | | `module.url_shortener_vpc.aws_eip.nat[1]` | | | `module.url_shortener_vpc.aws_eip.nat[2]` | | | `module.url_shortener_vpc.aws_flow_log.flow_logs[0]` | | | `module.url_shortener_vpc.aws_iam_policy.vpc_metrics_flow_logs_write_policy[0]` | | | `module.url_shortener_vpc.aws_iam_role.flow_logs[0]` | | | `module.url_shortener_vpc.aws_iam_role_policy_attachment.vpc_metrics_flow_logs_write_policy_attach[0]` | | | `module.url_shortener_vpc.aws_internet_gateway.gw` | | | `module.url_shortener_vpc.aws_nat_gateway.nat_gw[0]` | | | `module.url_shortener_vpc.aws_nat_gateway.nat_gw[1]` | | | `module.url_shortener_vpc.aws_nat_gateway.nat_gw[2]` | | | `module.url_shortener_vpc.aws_network_acl.main` | | | `module.url_shortener_vpc.aws_network_acl_rule.block_rdp[0]` | | | `module.url_shortener_vpc.aws_network_acl_rule.block_ssh[0]` | | | `module.url_shortener_vpc.aws_network_acl_rule.https_request_egress_443[0]` | | | `module.url_shortener_vpc.aws_network_acl_rule.https_request_in_ingress_443[0]` | | | `module.url_shortener_vpc.aws_network_acl_rule.https_request_in_ingress_ephemeral[0]` | | | `module.url_shortener_vpc.aws_network_acl_rule.https_request_in_response_egress_443[0]` | | | `module.url_shortener_vpc.aws_network_acl_rule.https_request_in_response_egress_ephemeral[0]` | | | `module.url_shortener_vpc.aws_network_acl_rule.https_request_out_egress_ephemeral[0]` | | | `module.url_shortener_vpc.aws_network_acl_rule.https_request_out_response_ingress_443[0]` | | | `module.url_shortener_vpc.aws_network_acl_rule.https_request_out_response_ingress_ephemeral[0]` | | | `module.url_shortener_vpc.aws_route.private_nat_gateway[0]` | | | `module.url_shortener_vpc.aws_route.private_nat_gateway[1]` | | | `module.url_shortener_vpc.aws_route.private_nat_gateway[2]` | | | `module.url_shortener_vpc.aws_route.public_internet_gateway` | | | `module.url_shortener_vpc.aws_route_table.private[0]` | | | `module.url_shortener_vpc.aws_route_table.private[1]` | | | `module.url_shortener_vpc.aws_route_table.private[2]` | | | `module.url_shortener_vpc.aws_route_table.public` | | | `module.url_shortener_vpc.aws_route_table_association.private[0]` | | | `module.url_shortener_vpc.aws_route_table_association.private[1]` | | | `module.url_shortener_vpc.aws_route_table_association.private[2]` | | | `module.url_shortener_vpc.aws_route_table_association.public[0]` | | | `module.url_shortener_vpc.aws_route_table_association.public[1]` | | | `module.url_shortener_vpc.aws_route_table_association.public[2]` | | | `module.url_shortener_vpc.aws_subnet.private[0]` | | | `module.url_shortener_vpc.aws_subnet.private[1]` | | | `module.url_shortener_vpc.aws_subnet.private[2]` | | | `module.url_shortener_vpc.aws_subnet.public[0]` | | | `module.url_shortener_vpc.aws_subnet.public[1]` | | | `module.url_shortener_vpc.aws_subnet.public[2]` | | | `module.url_shortener_vpc.aws_vpc.main` |

✂   Warning: plan has been truncated! See the full plan in the logs.

Show plan ```terraform Resource actions are indicated with the following symbols: + create <= read (data resources) Terraform will perform the following actions: # aws_flow_log.cloud_based_sensor will be created + resource "aws_flow_log" "cloud_based_sensor" { + arn = (known after apply) + id = (known after apply) + log_destination = "arn:aws:s3:::cbs-satellite-806721586252/vpc_flow_logs/" + log_destination_type = "s3" + log_format = "${vpc-id} ${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status} ${subnet-id} ${instance-id}" + log_group_name = (known after apply) + max_aggregation_interval = 600 + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + traffic_type = "ALL" + vpc_id = (known after apply) } # aws_security_group.api will be created + resource "aws_security_group" "api" { + arn = (known after apply) + description = "SG for the URL shortener API" + egress = (known after apply) + id = (known after apply) + ingress = (known after apply) + name = "url-shortener_api_sg" + name_prefix = (known after apply) + owner_id = (known after apply) + revoke_rules_on_delete = false + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_api_sg" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_api_sg" } + vpc_id = (known after apply) } # aws_security_group.vpc_endpoint will be created + resource "aws_security_group" "vpc_endpoint" { + arn = (known after apply) + description = "PrivateLink VPC endpoints" + egress = (known after apply) + id = (known after apply) + ingress = (known after apply) + name = "vpc_endpoints" + name_prefix = (known after apply) + owner_id = (known after apply) + revoke_rules_on_delete = false + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_api_sg" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_api_sg" + "Terraform" = "true" } + vpc_id = (known after apply) } # aws_security_group_rule.api_egress_internet will be created + resource "aws_security_group_rule" "api_egress_internet" { + cidr_blocks = [ + "0.0.0.0/0", ] + description = "Allow TCP egress connections to the internet on port 443" + from_port = 443 + id = (known after apply) + protocol = "tcp" + security_group_id = (known after apply) + security_group_rule_id = (known after apply) + self = false + source_security_group_id = (known after apply) + to_port = 443 + type = "egress" } # aws_security_group_rule.s3_private_endpoint_ingress will be created + resource "aws_security_group_rule" "s3_private_endpoint_ingress" { + description = "Ingress from the private S3 endpoint" + from_port = 443 + id = (known after apply) + prefix_list_ids = (known after apply) + protocol = "tcp" + security_group_id = (known after apply) + security_group_rule_id = (known after apply) + self = false + source_security_group_id = (known after apply) + to_port = 443 + type = "ingress" } # aws_security_group_rule.vpc_endpoint_dynamodb_ingress will be created + resource "aws_security_group_rule" "vpc_endpoint_dynamodb_ingress" { + description = "Ingress from the private DynamoDB endpoint" + from_port = 443 + id = (known after apply) + prefix_list_ids = (known after apply) + protocol = "tcp" + security_group_id = (known after apply) + security_group_rule_id = (known after apply) + self = false + source_security_group_id = (known after apply) + to_port = 443 + type = "ingress" } # aws_security_group_rule.vpc_endpoint_interface_ingress will be created + resource "aws_security_group_rule" "vpc_endpoint_interface_ingress" { + description = "Ingress from the API security group to the private interface endpoints" + from_port = 443 + id = (known after apply) + protocol = "tcp" + security_group_id = (known after apply) + security_group_rule_id = (known after apply) + self = false + source_security_group_id = (known after apply) + to_port = 443 + type = "ingress" } # aws_vpc_endpoint.dynamodb will be created + resource "aws_vpc_endpoint" "dynamodb" { + arn = (known after apply) + cidr_blocks = (known after apply) + dns_entry = (known after apply) + id = (known after apply) + ip_address_type = (known after apply) + network_interface_ids = (known after apply) + owner_id = (known after apply) + policy = (known after apply) + prefix_list_id = (known after apply) + private_dns_enabled = false + requester_managed = (known after apply) + route_table_ids = (known after apply) + security_group_ids = (known after apply) + service_name = "com.amazonaws.ca-central-1.dynamodb" + state = (known after apply) + subnet_ids = (known after apply) + tags_all = (known after apply) + vpc_endpoint_type = "Gateway" + vpc_id = (known after apply) + dns_options { + dns_record_ip_type = (known after apply) } } # aws_vpc_endpoint.logs will be created + resource "aws_vpc_endpoint" "logs" { + arn = (known after apply) + cidr_blocks = (known after apply) + dns_entry = (known after apply) + id = (known after apply) + ip_address_type = (known after apply) + network_interface_ids = (known after apply) + owner_id = (known after apply) + policy = (known after apply) + prefix_list_id = (known after apply) + private_dns_enabled = true + requester_managed = (known after apply) + route_table_ids = (known after apply) + security_group_ids = (known after apply) + service_name = "com.amazonaws.ca-central-1.logs" + state = (known after apply) + subnet_ids = (known after apply) + tags_all = (known after apply) + vpc_endpoint_type = "Interface" + vpc_id = (known after apply) + dns_options { + dns_record_ip_type = (known after apply) } } # aws_vpc_endpoint.s3 will be created + resource "aws_vpc_endpoint" "s3" { + arn = (known after apply) + cidr_blocks = (known after apply) + dns_entry = (known after apply) + id = (known after apply) + ip_address_type = (known after apply) + network_interface_ids = (known after apply) + owner_id = (known after apply) + policy = (known after apply) + prefix_list_id = (known after apply) + private_dns_enabled = false + requester_managed = (known after apply) + route_table_ids = (known after apply) + security_group_ids = (known after apply) + service_name = "com.amazonaws.ca-central-1.s3" + state = (known after apply) + subnet_ids = (known after apply) + tags_all = (known after apply) + vpc_endpoint_type = "Gateway" + vpc_id = (known after apply) + dns_options { + dns_record_ip_type = (known after apply) } } # module.url_shortener_vpc.data.aws_iam_policy_document.vpc_metrics_flow_logs_write[0] will be read during apply # (config refers to values not yet known) <= data "aws_iam_policy_document" "vpc_metrics_flow_logs_write" { + id = (known after apply) + json = (known after apply) + statement { + actions = [ + "logs:CreateLogStream", + "logs:DescribeLogGroups", + "logs:DescribeLogStreams", + "logs:PutLogEvents", ] + effect = "Allow" + resources = [ + (known after apply), + (known after apply), ] } } # module.url_shortener_vpc.aws_cloudwatch_log_group.flow_logs[0] will be created + resource "aws_cloudwatch_log_group" "flow_logs" { + arn = (known after apply) + id = (known after apply) + name = "url-shortener_flow_logs" + name_prefix = (known after apply) + retention_in_days = 30 + skip_destroy = false + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # module.url_shortener_vpc.aws_default_network_acl.default will be created + resource "aws_default_network_acl" "default" { + arn = (known after apply) + default_network_acl_id = (known after apply) + id = (known after apply) + owner_id = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_default_nacl" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_default_nacl" + "Terraform" = "true" } + vpc_id = (known after apply) } # module.url_shortener_vpc.aws_default_route_table.default will be created + resource "aws_default_route_table" "default" { + arn = (known after apply) + default_route_table_id = (known after apply) + id = (known after apply) + owner_id = (known after apply) + route = [] + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" + "name" = "url-shortener_default_route_table" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" + "name" = "url-shortener_default_route_table" } + vpc_id = (known after apply) } # module.url_shortener_vpc.aws_default_security_group.default will be created + resource "aws_default_security_group" "default" { + arn = (known after apply) + description = (known after apply) + egress = (known after apply) + id = (known after apply) + ingress = (known after apply) + name = (known after apply) + name_prefix = (known after apply) + owner_id = (known after apply) + revoke_rules_on_delete = false + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_default_sg" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_default_sg" + "Terraform" = "true" } + vpc_id = (known after apply) } # module.url_shortener_vpc.aws_eip.nat[0] will be created + resource "aws_eip" "nat" { + allocation_id = (known after apply) + association_id = (known after apply) + carrier_ip = (known after apply) + customer_owned_ip = (known after apply) + domain = (known after apply) + id = (known after apply) + instance = (known after apply) + network_border_group = (known after apply) + network_interface = (known after apply) + private_dns = (known after apply) + private_ip = (known after apply) + public_dns = (known after apply) + public_ip = (known after apply) + public_ipv4_pool = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-eip0" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-eip0" + "Terraform" = "true" } + vpc = true } # module.url_shortener_vpc.aws_eip.nat[1] will be created + resource "aws_eip" "nat" { + allocation_id = (known after apply) + association_id = (known after apply) + carrier_ip = (known after apply) + customer_owned_ip = (known after apply) + domain = (known after apply) + id = (known after apply) + instance = (known after apply) + network_border_group = (known after apply) + network_interface = (known after apply) + private_dns = (known after apply) + private_ip = (known after apply) + public_dns = (known after apply) + public_ip = (known after apply) + public_ipv4_pool = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-eip1" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-eip1" + "Terraform" = "true" } + vpc = true } # module.url_shortener_vpc.aws_eip.nat[2] will be created + resource "aws_eip" "nat" { + allocation_id = (known after apply) + association_id = (known after apply) + carrier_ip = (known after apply) + customer_owned_ip = (known after apply) + domain = (known after apply) + id = (known after apply) + instance = (known after apply) + network_border_group = (known after apply) + network_interface = (known after apply) + private_dns = (known after apply) + private_ip = (known after apply) + public_dns = (known after apply) + public_ip = (known after apply) + public_ipv4_pool = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-eip2" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-eip2" + "Terraform" = "true" } + vpc = true } # module.url_shortener_vpc.aws_flow_log.flow_logs[0] will be created + resource "aws_flow_log" "flow_logs" { + arn = (known after apply) + iam_role_arn = (known after apply) + id = (known after apply) + log_destination = (known after apply) + log_destination_type = "cloud-watch-logs" + log_format = (known after apply) + log_group_name = (known after apply) + max_aggregation_interval = 600 + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + traffic_type = "ALL" + vpc_id = (known after apply) } # module.url_shortener_vpc.aws_iam_policy.vpc_metrics_flow_logs_write_policy[0] will be created + resource "aws_iam_policy" "vpc_metrics_flow_logs_write_policy" { + arn = (known after apply) + description = "IAM policy for writing flow logs in CloudWatch" + id = (known after apply) + name = "VpcMetricsFlowLogsWrite" + path = "/" + policy = (known after apply) + policy_id = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # module.url_shortener_vpc.aws_iam_role.flow_logs[0] will be created + resource "aws_iam_role" "flow_logs" { + arn = (known after apply) + assume_role_policy = jsonencode( { + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "vpc-flow-logs.amazonaws.com" } + Sid = "" }, ] + Version = "2012-10-17" } ) + create_date = (known after apply) + force_detach_policies = false + id = (known after apply) + managed_policy_arns = (known after apply) + max_session_duration = 3600 + name = "url-shortener_flow_logs" + name_prefix = (known after apply) + path = "/" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + unique_id = (known after apply) + inline_policy { + name = (known after apply) + policy = (known after apply) } } # module.url_shortener_vpc.aws_iam_role_policy_attachment.vpc_metrics_flow_logs_write_policy_attach[0] will be created + resource "aws_iam_role_policy_attachment" "vpc_metrics_flow_logs_write_policy_attach" { + id = (known after apply) + policy_arn = (known after apply) + role = "url-shortener_flow_logs" } # module.url_shortener_vpc.aws_internet_gateway.gw will be created + resource "aws_internet_gateway" "gw" { + arn = (known after apply) + id = (known after apply) + owner_id = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_internet_gateway" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_internet_gateway" + "Terraform" = "true" } + vpc_id = (known after apply) } # module.url_shortener_vpc.aws_nat_gateway.nat_gw[0] will be created + resource "aws_nat_gateway" "nat_gw" { + allocation_id = (known after apply) + connectivity_type = "public" + id = (known after apply) + network_interface_id = (known after apply) + private_ip = (known after apply) + public_ip = (known after apply) + subnet_id = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-natgw-0" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-natgw-0" + "Terraform" = "true" } } # module.url_shortener_vpc.aws_nat_gateway.nat_gw[1] will be created + resource "aws_nat_gateway" "nat_gw" { + allocation_id = (known after apply) + connectivity_type = "public" + id = (known after apply) + network_interface_id = (known after apply) + private_ip = (known after apply) + public_ip = (known after apply) + subnet_id = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-natgw-1" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-natgw-1" + "Terraform" = "true" } } # module.url_shortener_vpc.aws_nat_gateway.nat_gw[2] will be created + resource "aws_nat_gateway" "nat_gw" { + allocation_id = (known after apply) + connectivity_type = "public" + id = (known after apply) + network_interface_id = (known after apply) + private_ip = (known after apply) + public_ip = (known after apply) + subnet_id = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-natgw-2" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener-natgw-2" + "Terraform" = "true" } } # module.url_shortener_vpc.aws_network_acl.main will be created + resource "aws_network_acl" "main" { + arn = (known after apply) + egress = (known after apply) + id = (known after apply) + ingress = (known after apply) + owner_id = (known after apply) + subnet_ids = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_main_nacl" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Name" = "url-shortener_main_nacl" + "Terraform" = "true" } + vpc_id = (known after apply) } # module.url_shortener_vpc.aws_network_acl_rule.block_rdp[0] will be created + resource "aws_network_acl_rule" "block_rdp" { + cidr_block = "0.0.0.0/0" + egress = false + from_port = 3389 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "deny" + rule_number = 51 + to_port = 3389 } # module.url_shortener_vpc.aws_network_acl_rule.block_ssh[0] will be created + resource "aws_network_acl_rule" "block_ssh" { + cidr_block = "0.0.0.0/0" + egress = false + from_port = 22 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "deny" + rule_number = 50 + to_port = 22 } # module.url_shortener_vpc.aws_network_acl_rule.https_request_egress_443[0] will be created + resource "aws_network_acl_rule" "https_request_egress_443" { + cidr_block = "0.0.0.0/0" + egress = true + from_port = 443 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "allow" + rule_number = 60 + to_port = 443 } # module.url_shortener_vpc.aws_network_acl_rule.https_request_in_ingress_443[0] will be created + resource "aws_network_acl_rule" "https_request_in_ingress_443" { + cidr_block = "0.0.0.0/0" + egress = false + from_port = 443 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "allow" + rule_number = 70 + to_port = 443 } # module.url_shortener_vpc.aws_network_acl_rule.https_request_in_ingress_ephemeral[0] will be created + resource "aws_network_acl_rule" "https_request_in_ingress_ephemeral" { + cidr_block = "10.0.0.0/16" + egress = false + from_port = 1024 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "allow" + rule_number = 71 + to_port = 65535 } # module.url_shortener_vpc.aws_network_acl_rule.https_request_in_response_egress_443[0] will be created + resource "aws_network_acl_rule" "https_request_in_response_egress_443" { + cidr_block = "10.0.0.0/16" + egress = true + from_port = 443 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "allow" + rule_number = 72 + to_port = 443 } # module.url_shortener_vpc.aws_network_acl_rule.https_request_in_response_egress_ephemeral[0] will be created + resource "aws_network_acl_rule" "https_request_in_response_egress_ephemeral" { + cidr_block = "0.0.0.0/0" + egress = true + from_port = 1024 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "allow" + rule_number = 73 + to_port = 65535 } # module.url_shortener_vpc.aws_network_acl_rule.https_request_out_egress_ephemeral[0] will be created + resource "aws_network_acl_rule" "https_request_out_egress_ephemeral" { + cidr_block = "10.0.0.0/16" + egress = true + from_port = 1024 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "allow" + rule_number = 61 + to_port = 65535 } # module.url_shortener_vpc.aws_network_acl_rule.https_request_out_response_ingress_443[0] will be created + resource "aws_network_acl_rule" "https_request_out_response_ingress_443" { + cidr_block = "10.0.0.0/16" + egress = false + from_port = 443 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "allow" + rule_number = 62 + to_port = 443 } # module.url_shortener_vpc.aws_network_acl_rule.https_request_out_response_ingress_ephemeral[0] will be created + resource "aws_network_acl_rule" "https_request_out_response_ingress_ephemeral" { + cidr_block = "0.0.0.0/0" + egress = false + from_port = 1024 + id = (known after apply) + network_acl_id = (known after apply) + protocol = "tcp" + rule_action = "allow" + rule_number = 63 + to_port = 65535 } # module.url_shortener_vpc.aws_route.private_nat_gateway[0] will be created + resource "aws_route" "private_nat_gateway" { + destination_cidr_block = "0.0.0.0/0" + id = (known after apply) + instance_id = (known after apply) + instance_owner_id = (known after apply) + nat_gateway_id = (known after apply) + network_interface_id = (known after apply) + origin = (known after apply) + route_table_id = (known after apply) + state = (known after apply) + timeouts { + create = "5m" } } # module.url_shortener_vpc.aws_route.private_nat_gateway[1] will be created + resource "aws_route" "private_nat_gateway" { +... ```
Show Conftest results ```sh WARN - plan.json - main - Missing Common Tags: ["aws_security_group.api"] WARN - plan.json - main - Missing Common Tags: ["aws_vpc_endpoint.dynamodb"] WARN - plan.json - main - Missing Common Tags: ["aws_vpc_endpoint.logs"] WARN - plan.json - main - Missing Common Tags: ["aws_vpc_endpoint.s3"] 21 tests, 17 passed, 4 warnings, 0 failures, 0 exceptions ```
github-actions[bot] commented 1 year ago

Production: alarms

✅   Terraform Init: success ✅   Terraform Validate: success ✅   Terraform Format: success ✅   Terraform Plan: success ✅   Conftest: success

Plan: 24 to add, 0 to change, 0 to destroy
Show summary | CHANGE | NAME | |--------|-------------------------------------------------------------------------------------| | add | `aws_cloudwatch_log_metric_filter.url_shortener_api_error` | | | `aws_cloudwatch_log_metric_filter.url_shortener_api_suspicious` | | | `aws_cloudwatch_log_metric_filter.url_shortener_api_warning` | | | `aws_cloudwatch_metric_alarm.cloudfront_ddos` | | | `aws_cloudwatch_metric_alarm.route53_ddos` | | | `aws_cloudwatch_metric_alarm.url_shoretener_api_suspicious` | | | `aws_cloudwatch_metric_alarm.url_shoretener_api_warning` | | | `aws_cloudwatch_metric_alarm.url_shortener_api_error` | | | `aws_cloudwatch_query_definition.api_errors` | | | `aws_cloudwatch_query_definition.api_suspicious` | | | `aws_cloudwatch_query_definition.api_warnings` | | | `aws_shield_protection.cloudfront_api` | | | `aws_shield_protection.route53_hosted_zone` | | | `aws_sns_topic.cloudwatch_warning` | | | `aws_sns_topic.cloudwatch_warning_us_east` | | | `aws_sns_topic_subscription.alert_warning` | | | `aws_sns_topic_subscription.alert_warning_us_east` | | | `module.cloudwatch_alarms_slack.aws_cloudwatch_log_group.notify_slack_lambda` | | | `module.cloudwatch_alarms_slack.aws_iam_policy.notify_slack_lambda` | | | `module.cloudwatch_alarms_slack.aws_iam_role.notify_slack_lambda` | | | `module.cloudwatch_alarms_slack.aws_iam_role_policy_attachment.notify_slack_lambda` | | | `module.cloudwatch_alarms_slack.aws_lambda_function.notify_slack` | | | `module.cloudwatch_alarms_slack.aws_lambda_permission.notify_slack[0]` | | | `module.cloudwatch_alarms_slack.aws_lambda_permission.notify_slack[1]` |
Show plan ```terraform Resource actions are indicated with the following symbols: + create <= read (data resources) Terraform will perform the following actions: # aws_cloudwatch_log_metric_filter.url_shortener_api_error will be created + resource "aws_cloudwatch_log_metric_filter" "url_shortener_api_error" { + id = (known after apply) + log_group_name = "/aws/lambda//aws/lambda/url-shortener-api" + name = "ErrorLoggedAPI" + pattern = "?ERROR ?Error ?error ?failed" + metric_transformation { + name = "ErrorLoggedAPI" + namespace = "UrlShortener" + unit = "None" + value = "1" } } # aws_cloudwatch_log_metric_filter.url_shortener_api_suspicious will be created + resource "aws_cloudwatch_log_metric_filter" "url_shortener_api_suspicious" { + id = (known after apply) + log_group_name = "/aws/lambda//aws/lambda/url-shortener-api" + name = "Suspicious" + pattern = "SUSPICIOUS" + metric_transformation { + name = "Suspicious" + namespace = "UrlShortener" + unit = "None" + value = "1" } } # aws_cloudwatch_log_metric_filter.url_shortener_api_warning will be created + resource "aws_cloudwatch_log_metric_filter" "url_shortener_api_warning" { + id = (known after apply) + log_group_name = "/aws/lambda//aws/lambda/url-shortener-api" + name = "WarningLoggedAPI" + pattern = "?WARNING ?Warning ?warning" + metric_transformation { + name = "WarningLoggedAPI" + namespace = "UrlShortener" + unit = "None" + value = "1" } } # aws_cloudwatch_metric_alarm.cloudfront_ddos will be created + resource "aws_cloudwatch_metric_alarm" "cloudfront_ddos" { + actions_enabled = true + alarm_actions = (known after apply) + alarm_description = "DDoS detection for CloudFront" + alarm_name = "DDoS CloudFront" + arn = (known after apply) + comparison_operator = "GreaterThanThreshold" + dimensions = { + "ResourceArn" = "arn:aws:cloudfront::123456789012:distribution/A2Z6W4OZAEKEKP" } + evaluate_low_sample_count_percentiles = (known after apply) + evaluation_periods = 1 + id = (known after apply) + metric_name = "DDoSDetected" + namespace = "AWS/DDoSProtection" + ok_actions = (known after apply) + period = 60 + statistic = "Sum" + tags_all = (known after apply) + threshold = 0 + treat_missing_data = "notBreaching" } # aws_cloudwatch_metric_alarm.route53_ddos will be created + resource "aws_cloudwatch_metric_alarm" "route53_ddos" { + actions_enabled = true + alarm_actions = (known after apply) + alarm_description = "DDoS detection for Route53" + alarm_name = "DDoS Route53" + arn = (known after apply) + comparison_operator = "GreaterThanThreshold" + dimensions = { + "ResourceArn" = "arn:aws:route53:::hostedzone/Z0129461HK2TKOF3BTTF" } + evaluate_low_sample_count_percentiles = (known after apply) + evaluation_periods = 1 + id = (known after apply) + metric_name = "DDoSDetected" + namespace = "AWS/DDoSProtection" + ok_actions = (known after apply) + period = 60 + statistic = "Sum" + tags_all = (known after apply) + threshold = 0 + treat_missing_data = "notBreaching" } # aws_cloudwatch_metric_alarm.url_shoretener_api_suspicious will be created + resource "aws_cloudwatch_metric_alarm" "url_shoretener_api_suspicious" { + actions_enabled = true + alarm_actions = (known after apply) + alarm_description = "Suspicious activity by users of the URL Shortener API lambda function over 5 minutes" + alarm_name = "URL Shortener API Suspicious" + arn = (known after apply) + comparison_operator = "GreaterThanOrEqualToThreshold" + evaluate_low_sample_count_percentiles = (known after apply) + evaluation_periods = 1 + id = (known after apply) + metric_name = "Suspicious" + namespace = "UrlShortener" + ok_actions = (known after apply) + period = 300 + statistic = "Sum" + tags_all = (known after apply) + threshold = 5 + treat_missing_data = "notBreaching" } # aws_cloudwatch_metric_alarm.url_shoretener_api_warning will be created + resource "aws_cloudwatch_metric_alarm" "url_shoretener_api_warning" { + actions_enabled = true + alarm_actions = (known after apply) + alarm_description = "Warnings logged by the URL Shortener API lambda function" + alarm_name = "URL Shortener API Warnings" + arn = (known after apply) + comparison_operator = "GreaterThanOrEqualToThreshold" + evaluate_low_sample_count_percentiles = (known after apply) + evaluation_periods = 1 + id = (known after apply) + metric_name = "WarningLoggedAPI" + namespace = "UrlShortener" + ok_actions = (known after apply) + period = 60 + statistic = "Sum" + tags_all = (known after apply) + threshold = 10 + treat_missing_data = "notBreaching" } # aws_cloudwatch_metric_alarm.url_shortener_api_error will be created + resource "aws_cloudwatch_metric_alarm" "url_shortener_api_error" { + actions_enabled = true + alarm_actions = (known after apply) + alarm_description = "Errors logged by the URL Shortener API lambda function" + alarm_name = "URL Shortener API Errors" + arn = (known after apply) + comparison_operator = "GreaterThanOrEqualToThreshold" + evaluate_low_sample_count_percentiles = (known after apply) + evaluation_periods = 1 + id = (known after apply) + metric_name = "ErrorLoggedAPI" + namespace = "UrlShortener" + ok_actions = (known after apply) + period = 60 + statistic = "Sum" + tags_all = (known after apply) + threshold = 1 + treat_missing_data = "notBreaching" } # aws_cloudwatch_query_definition.api_errors will be created + resource "aws_cloudwatch_query_definition" "api_errors" { + id = (known after apply) + log_group_names = [ + "/aws/lambda//aws/lambda/url-shortener-api", ] + name = "Errors API" + query_definition_id = (known after apply) + query_string = <<-EOT fields @timestamp, @message, @logStream | filter @message like /(?i)ERROR|FAILED/ | sort @timestamp desc | limit 20 EOT } # aws_cloudwatch_query_definition.api_suspicious will be created + resource "aws_cloudwatch_query_definition" "api_suspicious" { + id = (known after apply) + log_group_names = [ + "/aws/lambda//aws/lambda/url-shortener-api", ] + name = "Suspicious activity API" + query_definition_id = (known after apply) + query_string = <<-EOT fields @timestamp, @message, @logStream | filter @message like /SUSPICIOUS/ | sort @timestamp desc | limit 20 EOT } # aws_cloudwatch_query_definition.api_warnings will be created + resource "aws_cloudwatch_query_definition" "api_warnings" { + id = (known after apply) + log_group_names = [ + "/aws/lambda//aws/lambda/url-shortener-api", ] + name = "Warnings API" + query_definition_id = (known after apply) + query_string = <<-EOT fields @timestamp, @message, @logStream | filter @message like /WARNING/ | sort @timestamp desc | limit 20 EOT } # aws_shield_protection.cloudfront_api will be created + resource "aws_shield_protection" "cloudfront_api" { + arn = (known after apply) + id = (known after apply) + name = "CloudFrontAPI" + resource_arn = "arn:aws:cloudfront::123456789012:distribution/A2Z6W4OZAEKEKP" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # aws_shield_protection.route53_hosted_zone will be created + resource "aws_shield_protection" "route53_hosted_zone" { + arn = (known after apply) + id = (known after apply) + name = "Route53HostedZone" + resource_arn = "arn:aws:route53:::hostedzone/Z0129461HK2TKOF3BTTF" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # aws_sns_topic.cloudwatch_warning will be created + resource "aws_sns_topic" "cloudwatch_warning" { + arn = (known after apply) + content_based_deduplication = false + fifo_topic = false + id = (known after apply) + name = "cloudwatch-alarms-warning" + name_prefix = (known after apply) + owner = (known after apply) + policy = (known after apply) + signature_version = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tracing_config = (known after apply) } # aws_sns_topic.cloudwatch_warning_us_east will be created + resource "aws_sns_topic" "cloudwatch_warning_us_east" { + arn = (known after apply) + content_based_deduplication = false + fifo_topic = false + id = (known after apply) + name = "cloudwatch-alarms-warning" + name_prefix = (known after apply) + owner = (known after apply) + policy = (known after apply) + signature_version = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tracing_config = (known after apply) } # aws_sns_topic_subscription.alert_warning will be created + resource "aws_sns_topic_subscription" "alert_warning" { + arn = (known after apply) + confirmation_timeout_in_minutes = 1 + confirmation_was_authenticated = (known after apply) + endpoint = (known after apply) + endpoint_auto_confirms = false + filter_policy_scope = (known after apply) + id = (known after apply) + owner_id = (known after apply) + pending_confirmation = (known after apply) + protocol = "lambda" + raw_message_delivery = false + topic_arn = (known after apply) } # aws_sns_topic_subscription.alert_warning_us_east will be created + resource "aws_sns_topic_subscription" "alert_warning_us_east" { + arn = (known after apply) + confirmation_timeout_in_minutes = 1 + confirmation_was_authenticated = (known after apply) + endpoint = (known after apply) + endpoint_auto_confirms = false + filter_policy_scope = (known after apply) + id = (known after apply) + owner_id = (known after apply) + pending_confirmation = (known after apply) + protocol = "lambda" + raw_message_delivery = false + topic_arn = (known after apply) } # module.cloudwatch_alarms_slack.data.aws_iam_policy_document.notify_slack_lambda will be read during apply # (config refers to values not yet known) <= data "aws_iam_policy_document" "notify_slack_lambda" { + id = (known after apply) + json = (known after apply) + statement { + actions = [ + "logs:CreateLogStream", + "logs:PutLogEvents", ] + effect = "Allow" + resources = [ + (known after apply), ] } } # module.cloudwatch_alarms_slack.aws_cloudwatch_log_group.notify_slack_lambda will be created + resource "aws_cloudwatch_log_group" "notify_slack_lambda" { + arn = (known after apply) + id = (known after apply) + name = "/aws/lambda/url-shortener-cloudwatch-alarms-slack" + name_prefix = (known after apply) + retention_in_days = 14 + skip_destroy = false + tags = { + "CostCentre" = "url-shortener-production" } + tags_all = { + "CostCentre" = "url-shortener-production" } } # module.cloudwatch_alarms_slack.aws_iam_policy.notify_slack_lambda will be created + resource "aws_iam_policy" "notify_slack_lambda" { + arn = (known after apply) + id = (known after apply) + name = "NotifySlackLambda-url-shortener-cloudwatch-alarms-slack" + name_prefix = (known after apply) + path = "/" + policy = (known after apply) + policy_id = (known after apply) + tags_all = (known after apply) } # module.cloudwatch_alarms_slack.aws_iam_role.notify_slack_lambda will be created + resource "aws_iam_role" "notify_slack_lambda" { + arn = (known after apply) + assume_role_policy = jsonencode( { + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "lambda.amazonaws.com" } + Sid = "" }, ] + Version = "2012-10-17" } ) + create_date = (known after apply) + force_detach_policies = false + id = (known after apply) + managed_policy_arns = (known after apply) + max_session_duration = 3600 + name = "NotifySlackLambda-url-shortener-cloudwatch-alarms-slack" + name_prefix = (known after apply) + path = "/" + role_last_used = (known after apply) + tags_all = (known after apply) + unique_id = (known after apply) + inline_policy { + name = (known after apply) + policy = (known after apply) } } # module.cloudwatch_alarms_slack.aws_iam_role_policy_attachment.notify_slack_lambda will be created + resource "aws_iam_role_policy_attachment" "notify_slack_lambda" { + id = (known after apply) + policy_arn = (known after apply) + role = "NotifySlackLambda-url-shortener-cloudwatch-alarms-slack" } # module.cloudwatch_alarms_slack.aws_lambda_function.notify_slack will be created + resource "aws_lambda_function" "notify_slack" { + architectures = (known after apply) + arn = (known after apply) + description = "Lambda function to post CloudWatch alarm notifications to a Slack channel." + filename = "/tmp/notify_slack.py.zip" + function_name = "url-shortener-cloudwatch-alarms-slack" + handler = "notify_slack.lambda_handler" + id = (known after apply) + invoke_arn = (known after apply) + last_modified = (known after apply) + memory_size = 128 + package_type = "Zip" + publish = false + qualified_arn = (known after apply) + qualified_invoke_arn = (known after apply) + reserved_concurrent_executions = -1 + role = (known after apply) + runtime = "python3.8" + signing_job_arn = (known after apply) + signing_profile_version_arn = (known after apply) + skip_destroy = false + source_code_hash = "iC0Ta5b8fs9u6i/c3LA3/Tk8BUHfS6Jgq4NF8At0CBo=" + source_code_size = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" } + tags_all = { + "CostCentre" = "url-shortener-production" } + timeout = 30 + version = (known after apply) + environment { + variables = { + "LOG_EVENTS" = "True" + "PROJECT_NAME" = "url-shortener" + "SLACK_WEBHOOK_URL" = (sensitive value) } } + ephemeral_storage { + size = (known after apply) } + tracing_config { + mode = (known after apply) } } # module.cloudwatch_alarms_slack.aws_lambda_permission.notify_slack[0] will be created + resource "aws_lambda_permission" "notify_slack" { + action = "lambda:InvokeFunction" + function_name = "url-shortener-cloudwatch-alarms-slack" + id = (known after apply) + principal = "sns.amazonaws.com" + source_arn = (known after apply) + statement_id = "AllowExecutionFromSNS-url-shortener-cloudwatch-alarms-slack-0" + statement_id_prefix = (known after apply) } # module.cloudwatch_alarms_slack.aws_lambda_permission.notify_slack[1] will be created + resource "aws_lambda_permission" "notify_slack" { + action = "lambda:InvokeFunction" + function_name = "url-shortener-cloudwatch-alarms-slack" + id = (known after apply) + principal = "sns.amazonaws.com" + source_arn = (known after apply) + statement_id = "AllowExecutionFromSNS-url-shortener-cloudwatch-alarms-slack-1" + statement_id_prefix = (known after apply) } Plan: 24 to add, 0 to change, 0 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan.tfplan To perform exactly these actions, run the following command to apply: terraform apply "plan.tfplan" Releasing state lock. This may take a few moments... ```
Show Conftest results ```sh WARN - plan.json - main - Cloudwatch log metric pattern is invalid: ["aws_cloudwatch_log_metric_filter.url_shortener_api_error"] WARN - plan.json - main - Cloudwatch log metric pattern is invalid: ["aws_cloudwatch_log_metric_filter.url_shortener_api_warning"] WARN - plan.json - main - Missing Common Tags: ["aws_cloudwatch_metric_alarm.cloudfront_ddos"] WARN - plan.json - main - Missing Common Tags: ["aws_cloudwatch_metric_alarm.route53_ddos"] WARN - plan.json - main - Missing Common Tags: ["aws_cloudwatch_metric_alarm.url_shoretener_api_suspicious"] WARN - plan.json - main - Missing Common Tags: ["aws_cloudwatch_metric_alarm.url_shoretener_api_warning"] WARN - plan.json - main - Missing Common Tags: ["aws_cloudwatch_metric_alarm.url_shortener_api_error"] WARN - plan.json - main - Missing Common Tags: ["module.cloudwatch_alarms_slack.aws_cloudwatch_log_group.notify_slack_lambda"] WARN - plan.json - main - Missing Common Tags: ["module.cloudwatch_alarms_slack.aws_iam_policy.notify_slack_lambda"] WARN - plan.json - main - Missing Common Tags: ["module.cloudwatch_alarms_slack.aws_iam_role.notify_slack_lambda"] WARN - plan.json - main - Missing Common Tags: ["module.cloudwatch_alarms_slack.aws_lambda_function.notify_slack"] 27 tests, 16 passed, 11 warnings, 0 failures, 0 exceptions ```
github-actions[bot] commented 1 year ago

Production: api

✅   Terraform Init: success ✅   Terraform Validate: success ✅   Terraform Format: success ✅   Terraform Plan: success ✅   Conftest: success

⚠️   Warning: resources will be destroyed by this change!

Plan: 23 to add, 0 to change, 2 to destroy
Show summary | CHANGE | NAME | |--------|-----------------------------------------------------------------------------------------------------| | add | `aws_cloudwatch_log_subscription_filter.api_request` | | | `aws_lambda_function_url.url_shortener_url` | | | `aws_ssm_parameter.auth_token_app` | | | `aws_ssm_parameter.auth_token_notify` | | | `aws_ssm_parameter.cloudfront_header` | | | `aws_ssm_parameter.hashing_peppers` | | | `aws_ssm_parameter.notify_api_key` | | | `aws_ssm_parameter.notify_contact_email` | | | `module.sentinel_forwarder.aws_cloudwatch_log_group.sentinel_forwarder_lambda` | | | `module.sentinel_forwarder.aws_iam_policy.sentinel_forwarder_lambda` | | | `module.sentinel_forwarder.aws_iam_role.sentinel_forwarder_lambda` | | | `module.sentinel_forwarder.aws_iam_role_policy_attachment.sentinel_forwarder_lambda` | | | `module.sentinel_forwarder.aws_lambda_function.sentinel_forwarder` | | | `module.sentinel_forwarder.aws_lambda_permission.sentinel_forwarder_cloudwatch_log_subscription[0]` | | | `module.url_shortener_lambda.aws_cloudwatch_log_group.this` | | | `module.url_shortener_lambda.aws_iam_policy.policies[0]` | | | `module.url_shortener_lambda.aws_iam_policy.vpc_policies[0]` | | | `module.url_shortener_lambda.aws_iam_role.this` | | | `module.url_shortener_lambda.aws_iam_role_policy_attachment.AWSLambdaVPCAccessExecutionRole[0]` | | | `module.url_shortener_lambda.aws_iam_role_policy_attachment.attachments[0]` | | | `module.url_shortener_lambda.aws_iam_role_policy_attachment.lambda_insights[0]` | | | `module.url_shortener_lambda.aws_iam_role_policy_attachment.vpc_policies[0]` | | | `module.url_shortener_lambda.aws_lambda_function.this` | | delete | `aws_iam_role_policy_attachment.admin` | | | `module.gh_oidc_roles.aws_iam_role.this["OIDCGithubWorkflowRole"]` |
Show plan ```terraform Resource actions are indicated with the following symbols: + create - destroy <= read (data resources) Terraform will perform the following actions: # data.aws_iam_policy_document.api_policies will be read during apply # (config refers to values not yet known) <= data "aws_iam_policy_document" "api_policies" { + id = (known after apply) + json = (known after apply) + statement { + actions = [ + "dynamodb:DeleteItem", + "dynamodb:DescribeTable", + "dynamodb:GetItem", + "dynamodb:PutItem", + "dynamodb:Query", + "dynamodb:UpdateItem", ] + effect = "Allow" + resources = [ + "arn:aws:dynamodb:ca-central-1:806721586252:table/", + "arn:aws:dynamodb:ca-central-1:806721586252:table//index/emailIndex", ] } + statement { + actions = [ + "ssm:GetParameters", ] + effect = "Allow" + resources = [ + (known after apply), + (known after apply), + (known after apply), + (known after apply), + (known after apply), + (known after apply), ] } } # aws_cloudwatch_log_subscription_filter.api_request will be created + resource "aws_cloudwatch_log_subscription_filter" "api_request" { + destination_arn = (known after apply) + distribution = "Random" + filter_pattern = "?INFO ?WARNING ?ERROR" + id = (known after apply) + log_group_name = "/aws/lambda/url-shortener-api" + name = "API request" + role_arn = (known after apply) } # aws_iam_role_policy_attachment.admin will be destroyed # (because aws_iam_role_policy_attachment.admin is not in configuration) - resource "aws_iam_role_policy_attachment" "admin" { - id = "OIDCGithubWorkflowRole-20230131225831523000000001" -> null - policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" -> null - role = "OIDCGithubWorkflowRole" -> null } # aws_lambda_function_url.url_shortener_url will be created + resource "aws_lambda_function_url" "url_shortener_url" { + authorization_type = "NONE" + function_arn = (known after apply) + function_name = "url-shortener-api" + function_url = (known after apply) + id = (known after apply) + url_id = (known after apply) } # aws_ssm_parameter.auth_token_app will be created + resource "aws_ssm_parameter" "auth_token_app" { + arn = (known after apply) + data_type = (known after apply) + id = (known after apply) + insecure_value = (known after apply) + key_id = (known after apply) + name = "auth_token_app" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tier = (known after apply) + type = "SecureString" + value = (sensitive value) + version = (known after apply) } # aws_ssm_parameter.auth_token_notify will be created + resource "aws_ssm_parameter" "auth_token_notify" { + arn = (known after apply) + data_type = (known after apply) + id = (known after apply) + insecure_value = (known after apply) + key_id = (known after apply) + name = "auth_token_notify" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tier = (known after apply) + type = "SecureString" + value = (sensitive value) + version = (known after apply) } # aws_ssm_parameter.cloudfront_header will be created + resource "aws_ssm_parameter" "cloudfront_header" { + arn = (known after apply) + data_type = (known after apply) + id = (known after apply) + insecure_value = (known after apply) + key_id = (known after apply) + name = "cloudfront_header" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tier = (known after apply) + type = "SecureString" + value = (sensitive value) + version = (known after apply) } # aws_ssm_parameter.hashing_peppers will be created + resource "aws_ssm_parameter" "hashing_peppers" { + arn = (known after apply) + data_type = (known after apply) + id = (known after apply) + insecure_value = (known after apply) + key_id = (known after apply) + name = "hashing_peppers" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tier = (known after apply) + type = "SecureString" + value = (sensitive value) + version = (known after apply) } # aws_ssm_parameter.notify_api_key will be created + resource "aws_ssm_parameter" "notify_api_key" { + arn = (known after apply) + data_type = (known after apply) + id = (known after apply) + insecure_value = (known after apply) + key_id = (known after apply) + name = "notify_api_key" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tier = (known after apply) + type = "SecureString" + value = (sensitive value) + version = (known after apply) } # aws_ssm_parameter.notify_contact_email will be created + resource "aws_ssm_parameter" "notify_contact_email" { + arn = (known after apply) + data_type = (known after apply) + id = (known after apply) + insecure_value = (known after apply) + key_id = (known after apply) + name = "notify_contact_email" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tier = (known after apply) + type = "SecureString" + value = (sensitive value) + version = (known after apply) } # module.gh_oidc_roles.aws_iam_role.this["OIDCGithubWorkflowRole"] will be destroyed # (because aws_iam_role.this is not in configuration) - resource "aws_iam_role" "this" { - arn = "arn:aws:iam::806721586252:role/OIDCGithubWorkflowRole" -> null - assume_role_policy = jsonencode( { - Statement = [ - { - Action = "sts:AssumeRoleWithWebIdentity" - Condition = { - StringLike = { - "token.actions.githubusercontent.com:sub" = [ - "repo:cds-snc/url-shortener:*", ] } } - Effect = "Allow" - Principal = { - Federated = "arn:aws:iam::806721586252:oidc-provider/token.actions.githubusercontent.com" } - Sid = "" }, ] - Version = "2012-10-17" } ) -> null - create_date = "2023-01-31T22:58:30Z" -> null - force_detach_policies = false -> null - id = "OIDCGithubWorkflowRole" -> null - managed_policy_arns = [ - "arn:aws:iam::aws:policy/AdministratorAccess", ] -> null - max_session_duration = 3600 -> null - name = "OIDCGithubWorkflowRole" -> null - path = "/" -> null - tags = { - "CostCentre" = "url-shortener-production" - "Terraform" = "true" } -> null - tags_all = { - "CostCentre" = "url-shortener-production" - "Terraform" = "true" } -> null - unique_id = "AROA3XVC2QRGCTTGHJREF" -> null } # module.sentinel_forwarder.data.aws_iam_policy_document.sentinel_forwarder_lambda will be read during apply # (config refers to values not yet known) <= data "aws_iam_policy_document" "sentinel_forwarder_lambda" { + id = (known after apply) + json = (known after apply) + statement { + actions = [ + "logs:CreateLogStream", + "logs:PutLogEvents", ] + effect = "Allow" + resources = [ + (known after apply), ] } + statement { + actions = [ + "xray:GetSamplingRules", + "xray:GetSamplingStatisticSummaries", + "xray:GetSamplingTargets", + "xray:PutTelemetryRecords", + "xray:PutTraceSegments", ] + effect = "Allow" + resources = [ + "*", ] } } # module.sentinel_forwarder.aws_cloudwatch_log_group.sentinel_forwarder_lambda will be created + resource "aws_cloudwatch_log_group" "sentinel_forwarder_lambda" { + arn = (known after apply) + id = (known after apply) + name = "/aws/lambda/sentinel-cloudwatch-forwarder" + name_prefix = (known after apply) + retention_in_days = 14 + skip_destroy = false + tags = { + "CostCentre" = "url-shortener-production" } + tags_all = { + "CostCentre" = "url-shortener-production" } } # module.sentinel_forwarder.aws_iam_policy.sentinel_forwarder_lambda will be created + resource "aws_iam_policy" "sentinel_forwarder_lambda" { + arn = (known after apply) + id = (known after apply) + name = "SentinelForwarderLambda-sentinel-cloudwatch-forwarder" + path = "/" + policy = (known after apply) + policy_id = (known after apply) + tags_all = (known after apply) } # module.sentinel_forwarder.aws_iam_role.sentinel_forwarder_lambda will be created + resource "aws_iam_role" "sentinel_forwarder_lambda" { + arn = (known after apply) + assume_role_policy = jsonencode( { + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "lambda.amazonaws.com" } + Sid = "" }, ] + Version = "2012-10-17" } ) + create_date = (known after apply) + force_detach_policies = false + id = (known after apply) + managed_policy_arns = (known after apply) + max_session_duration = 3600 + name = "SentinelForwarderLambda-sentinel-cloudwatch-forwarder" + name_prefix = (known after apply) + path = "/" + tags_all = (known after apply) + unique_id = (known after apply) + inline_policy { + name = (known after apply) + policy = (known after apply) } } # module.sentinel_forwarder.aws_iam_role_policy_attachment.sentinel_forwarder_lambda will be created + resource "aws_iam_role_policy_attachment" "sentinel_forwarder_lambda" { + id = (known after apply) + policy_arn = (known after apply) + role = "SentinelForwarderLambda-sentinel-cloudwatch-forwarder" } # module.sentinel_forwarder.aws_lambda_function.sentinel_forwarder will be created + resource "aws_lambda_function" "sentinel_forwarder" { + architectures = (known after apply) + arn = (known after apply) + description = "Lambda function to forward AWS logs to Azure Sentinel" + filename = "/tmp/sentinel_forwarder.py.zip" + function_name = "sentinel-cloudwatch-forwarder" + handler = "sentinel_forwarder.lambda_handler" + id = (known after apply) + invoke_arn = (known after apply) + last_modified = (known after apply) + layers = [ + "arn:aws:lambda:ca-central-1:283582579564:layer:aws-sentinel-connector-layer:54", ] + memory_size = 128 + package_type = "Zip" + publish = false + qualified_arn = (known after apply) + qualified_invoke_arn = (known after apply) + reserved_concurrent_executions = -1 + role = (known after apply) + runtime = "python3.9" + signing_job_arn = (known after apply) + signing_profile_version_arn = (known after apply) + source_code_hash = "liR4yJNhp6SJtCjkSwnH0xGC0q00Uxebs1Cyqv8JLDw=" + source_code_size = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" } + tags_all = { + "CostCentre" = "url-shortener-production" } + timeout = 30 + version = (known after apply) + environment { + variables = { + "CUSTOMER_ID" = (sensitive value) + "LOG_TYPE" = "ApplicationLog" + "SHARED_KEY" = (sensitive value) } } + ephemeral_storage { + size = (known after apply) } + tracing_config { + mode = "Active" } } # module.sentinel_forwarder.aws_lambda_permission.sentinel_forwarder_cloudwatch_log_subscription[0] will be created + resource "aws_lambda_permission" "sentinel_forwarder_cloudwatch_log_subscription" { + action = "lambda:InvokeFunction" + function_name = "sentinel-cloudwatch-forwarder" + id = (known after apply) + principal = "logs.ca-central-1.amazonaws.com" + source_arn = "arn:aws:logs:ca-central-1:806721586252:log-group:/aws/lambda/url-shortener-api:*" + statement_id = "AllowExecutionFromCloudWatchLogs-sentinel-cloudwatch-forwarder-0" + statement_id_prefix = (known after apply) } # module.url_shortener_lambda.aws_cloudwatch_log_group.this will be created + resource "aws_cloudwatch_log_group" "this" { + arn = (known after apply) + id = (known after apply) + name = "/aws/lambda/url-shortener-api" + name_prefix = (known after apply) + retention_in_days = 14 + skip_destroy = false + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # module.url_shortener_lambda.aws_iam_policy.policies[0] will be created + resource "aws_iam_policy" "policies" { + arn = (known after apply) + id = (known after apply) + name = "url-shortener-api-0" + path = "/" + policy = (known after apply) + policy_id = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # module.url_shortener_lambda.aws_iam_policy.vpc_policies[0] will be created + resource "aws_iam_policy" "vpc_policies" { + arn = (known after apply) + id = (known after apply) + name = "url-shortener-api_vpc" + path = "/" + policy = jsonencode( { + Statement = [ + { + Action = [ + "ecr:GetDownloadUrlForlayer", + "ecr:BatchGetImage", ] + Effect = "Allow" + Resource = "arn:aws:ecr:ca-central-1:806721586252:repository/url-shortener/api" + Sid = "ECRImageAccess" }, ] + Version = "2012-10-17" } ) + policy_id = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # module.url_shortener_lambda.aws_iam_role.this will be created + resource "aws_iam_role" "this" { + arn = (known after apply) + assume_role_policy = jsonencode( { + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "lambda.amazonaws.com" } + Sid = "" }, ] + Version = "2012-10-17" } ) + create_date = (known after apply) + force_detach_policies = false + id = (known after apply) + managed_policy_arns = (known after apply) + max_session_duration = 3600 + name = "url-shortener-api" + name_prefix = (known after apply) + path = "/" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + unique_id = (known after apply) + inline_policy { + name = (known after apply) + policy = (known after apply) } } # module.url_shortener_lambda.aws_iam_role_policy_attachment.AWSLambdaVPCAccessExecutionRole[0] will be created + resource "aws_iam_role_policy_attachment" "AWSLambdaVPCAccessExecutionRole" { + id = (known after apply) + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" + role = "url-shortener-api" } # module.url_shortener_lambda.aws_iam_role_policy_attachment.attachments[0] will be created + resource "aws_iam_role_policy_attachment" "attachments" { + id = (known after apply) + policy_arn = (known after apply) + role = "url-shortener-api" } # module.url_shortener_lambda.aws_iam_role_policy_attachment.lambda_insights[0] will be created + resource "aws_iam_role_policy_attachment" "lambda_insights" { + id = (known after apply) + policy_arn = "arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy" + role = "url-shortener-api" } # module.url_shortener_lambda.aws_iam_role_policy_attachment.vpc_policies[0] will be created + resource "aws_iam_role_policy_attachment" "vpc_policies" { + id = (known after apply) + policy_arn = (known after apply) + role = "url-shortener-api" } # module.url_shortener_lambda.aws_lambda_function.this will be created + resource "aws_lambda_function" "this" { + architectures = [ + "x86_64", ] + arn = (known after apply) + function_name = "url-shortener-api" + id = (known after apply) + image_uri = "806721586252.dkr.ecr.ca-central-1.amazonaws.com/url-shortener/api:latest" + invoke_arn = (known after apply) + last_modified = (known after apply) + memory_size = 3008 + package_type = "Image" + publish = false + qualified_arn = (known after apply) + qualified_invoke_arn = (known after apply) + reserved_concurrent_executions = -1 + role = (known after apply) + signing_job_arn = (known after apply) + signing_profile_version_arn = (known after apply) + source_code_hash = (known after apply) + source_code_size = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + timeout = 300 + version = (known after apply) + environment { + variables = { + "ALLOWED_DOMAINS" = "canada.ca,gc.ca,cds-snc.ca" + "NOTIFY_CONTACT_TEMPLATE" = "47a6be8d-c472-426e-81bb-af1bb89aca87" + "NOTIFY_MAGIC_LINK_TEMPLATE" = "092f910a-c3cd-4a91-901d-a2d93fe1e603" + "SHORTENER_DOMAIN" = "https://o.alpha.canada.ca/" + "SHORTENER_PATH_LENGTH" = "8" } } + ephemeral_storage { + size = 512 } + tracing_config { + mode = "PassThrough" } + vpc_config { + security_group_ids = [ + "", ] + subnet_ids = [ + "", ] + vpc_id = (known after apply) } } Plan: 23 to add, 0 to change, 2 to destroy. Changes to Outputs: + function_arn = (known after apply) + function_name = "url-shortener-api" + function_url = (known after apply) + invoke_arn = (known after apply) ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan.tfplan To perform exactly these actions, run the following command to apply: terraform apply "plan.tfplan" Releasing state lock. This may take a few moments... ```
Show Conftest results ```sh WARN - plan.json - main - Missing Common Tags: ["module.sentinel_forwarder.aws_cloudwatch_log_group.sentinel_forwarder_lambda"] WARN - plan.json - main - Missing Common Tags: ["module.sentinel_forwarder.aws_iam_policy.sentinel_forwarder_lambda"] WARN - plan.json - main - Missing Common Tags: ["module.sentinel_forwarder.aws_iam_role.sentinel_forwarder_lambda"] WARN - plan.json - main - Missing Common Tags: ["module.sentinel_forwarder.aws_lambda_function.sentinel_forwarder"] 21 tests, 17 passed, 4 warnings, 0 failures, 0 exceptions ```
github-actions[bot] commented 1 year ago

Production: cloudfront

✅   Terraform Init: success ✅   Terraform Validate: success ✅   Terraform Format: success ✅   Terraform Plan: success ✅   Conftest: success

Plan: 25 to add, 0 to change, 0 to destroy
Show summary | CHANGE | NAME | |--------|----------------------------------------------------------------------------------------------| | add | `aws_acm_certificate.url_shortener_certificate` | | | `aws_acm_certificate_validation.url_shortener_certificate_validation` | | | `aws_cloudfront_distribution.url_shortener_api` | | | `aws_cloudfront_response_headers_policy.security_headers_api` | | | `aws_iam_policy.write_waf_logs` | | | `aws_iam_role.waf_log_role` | | | `aws_iam_role_policy_attachment.write_waf_logs` | | | `aws_kinesis_firehose_delivery_stream.api` | | | `aws_route53_record.url_shortener_A` | | | `aws_route53_record.url_shortener_dns_validation["*.o.alpha.canada.ca"]` | | | `aws_route53_record.url_shortener_dns_validation["o.alpha.canada.ca"]` | | | `aws_wafv2_regex_pattern_set.login_uri_paths` | | | `aws_wafv2_regex_pattern_set.valid_uri_paths` | | | `aws_wafv2_web_acl.api_waf` | | | `aws_wafv2_web_acl_logging_configuration.api` | | | `module.resolver_dns.aws_cloudwatch_log_group.route53_vpc_dns` | | | `module.resolver_dns.aws_cloudwatch_log_resource_policy.route53_vpc_dns` | | | `module.resolver_dns.aws_route53_resolver_firewall_domain_list.allowed[0]` | | | `module.resolver_dns.aws_route53_resolver_firewall_domain_list.blocked[0]` | | | `module.resolver_dns.aws_route53_resolver_firewall_rule.allowed[0]` | | | `module.resolver_dns.aws_route53_resolver_firewall_rule.blocked[0]` | | | `module.resolver_dns.aws_route53_resolver_firewall_rule_group.firewall_rules[0]` | | | `module.resolver_dns.aws_route53_resolver_firewall_rule_group_association.firewall_rules[0]` | | | `module.resolver_dns.aws_route53_resolver_query_log_config.route53_vpc_dns` | | | `module.resolver_dns.aws_route53_resolver_query_log_config_association.route53_vpc_dns` |

✂   Warning: plan has been truncated! See the full plan in the logs.

Show plan ```terraform Resource actions are indicated with the following symbols: + create <= read (data resources) Terraform will perform the following actions: # aws_acm_certificate.url_shortener_certificate will be created + resource "aws_acm_certificate" "url_shortener_certificate" { + arn = (known after apply) + domain_name = "o.alpha.canada.ca" + domain_validation_options = [ + { + domain_name = "*.o.alpha.canada.ca" + resource_record_name = (known after apply) + resource_record_type = (known after apply) + resource_record_value = (known after apply) }, + { + domain_name = "o.alpha.canada.ca" + resource_record_name = (known after apply) + resource_record_type = (known after apply) + resource_record_value = (known after apply) }, ] + id = (known after apply) + key_algorithm = (known after apply) + not_after = (known after apply) + not_before = (known after apply) + pending_renewal = (known after apply) + renewal_eligibility = (known after apply) + renewal_summary = (known after apply) + status = (known after apply) + subject_alternative_names = [ + "*.o.alpha.canada.ca", + "o.alpha.canada.ca", ] + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + type = (known after apply) + validation_emails = (known after apply) + validation_method = "DNS" + options { + certificate_transparency_logging_preference = (known after apply) } } # aws_acm_certificate_validation.url_shortener_certificate_validation will be created + resource "aws_acm_certificate_validation" "url_shortener_certificate_validation" { + certificate_arn = (known after apply) + id = (known after apply) + validation_record_fqdns = (known after apply) } # aws_cloudfront_distribution.url_shortener_api will be created + resource "aws_cloudfront_distribution" "url_shortener_api" { + aliases = [ + "o.alpha.canada.ca", ] + arn = (known after apply) + caller_reference = (known after apply) + domain_name = (known after apply) + enabled = true + etag = (known after apply) + hosted_zone_id = (known after apply) + http_version = "http2" + id = (known after apply) + in_progress_validation_batches = (known after apply) + is_ipv6_enabled = false + last_modified_time = (known after apply) + price_class = "PriceClass_100" + retain_on_delete = false + status = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + trusted_key_groups = (known after apply) + trusted_signers = (known after apply) + wait_for_deployment = true + web_acl_id = (known after apply) + default_cache_behavior { + allowed_methods = [ + "DELETE", + "GET", + "HEAD", + "OPTIONS", + "PATCH", + "POST", + "PUT", ] + cache_policy_id = "4135ea2d-6df8-44a3-9df3-4b5a84be39ad" + cached_methods = [ + "GET", + "HEAD", ] + compress = true + default_ttl = (known after apply) + max_ttl = (known after apply) + min_ttl = 0 + origin_request_policy_id = "b689b0a8-53d0-40ab-baf2-68738e2966ac" + response_headers_policy_id = (known after apply) + target_origin_id = "url-shortener-api" + trusted_key_groups = (known after apply) + trusted_signers = (known after apply) + viewer_protocol_policy = "redirect-to-https" } + ordered_cache_behavior { + allowed_methods = [ + "GET", + "HEAD", ] + cached_methods = [ + "GET", + "HEAD", ] + compress = true + default_ttl = 0 + max_ttl = 0 + min_ttl = 0 + path_pattern = "/healthcheck" + response_headers_policy_id = (known after apply) + target_origin_id = "url-shortener-api" + viewer_protocol_policy = "redirect-to-https" + forwarded_values { + headers = (known after apply) + query_string = false + query_string_cache_keys = (known after apply) + cookies { + forward = "none" } } } + origin { # At least one attribute in this block is (or was) sensitive, # so its contents will not be displayed. } + restrictions { + geo_restriction { + locations = (known after apply) + restriction_type = "none" } } + viewer_certificate { + acm_certificate_arn = (known after apply) + minimum_protocol_version = "TLSv1.2_2021" + ssl_support_method = "sni-only" } } # aws_cloudfront_response_headers_policy.security_headers_api will be created + resource "aws_cloudfront_response_headers_policy" "security_headers_api" { + etag = (known after apply) + id = (known after apply) + name = "url-shortener-security-headers-api" + security_headers_config { + content_security_policy { + content_security_policy = "report-uri https://csp-report-to.security.cdssandbox.xyz/report; default-src 'none'; script-src 'self' 'unsafe-inline' https://unpkg.com/@cdssnc/ https://o.alpha.canada.ca/static/js/ https://kit.fontawesome.com; font-src 'self' https://fonts.googleapis.com https://fonts.gstatic.com https://kit.fontawesome.com https://ka-f.fontawesome.com https://unpkg.com/font-awesome@4.7.0/; connect-src 'self' https://ka-f.fontawesome.com; img-src 'self' https://o.alpha.canada.ca/static/img/ data: w3.org/svg/2000; style-src 'self' 'unsafe-inline' https://o.alpha.canada.ca/static/css/ https://unpkg.com/@cdssnc/ https://unpkg.com/font-awesome/ https://kit.fontawesome.com https://fonts.googleapis.com; frame-ancestors 'self'; form-action 'self';" + override = false } + content_type_options { + override = true } + frame_options { + frame_option = "DENY" + override = true } + referrer_policy { + override = true + referrer_policy = "same-origin" } + strict_transport_security { + access_control_max_age_sec = 31536000 + include_subdomains = true + override = true + preload = true } + xss_protection { + mode_block = true + override = true + protection = true } } } # aws_iam_policy.write_waf_logs will be created + resource "aws_iam_policy" "write_waf_logs" { + arn = (known after apply) + description = "Allow Firehose to write WAF logs to S3" + id = (known after apply) + name = "url-shortener-waf-logs" + name_prefix = (known after apply) + path = "/" + policy = jsonencode( { + Statement = [ + { + Action = "s3:ListBucket" + Effect = "Allow" + Resource = "arn:aws:s3:::cbs-satellite-806721586252" + Sid = "" }, + { + Action = [ + "s3:PutObject*", + "s3:GetObject*", ] + Effect = "Allow" + Resource = "arn:aws:s3:::cbs-satellite-806721586252/waf_acl_logs/*" + Sid = "" }, ] + Version = "2012-10-17" } ) + policy_id = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # aws_iam_role.waf_log_role will be created + resource "aws_iam_role" "waf_log_role" { + arn = (known after apply) + assume_role_policy = jsonencode( { + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "firehose.amazonaws.com" } + Sid = "" }, ] + Version = "2012-10-17" } ) + create_date = (known after apply) + force_detach_policies = false + id = (known after apply) + managed_policy_arns = (known after apply) + max_session_duration = 3600 + name = "url-shortener-waf-logs" + name_prefix = (known after apply) + path = "/" + role_last_used = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + unique_id = (known after apply) + inline_policy { + name = (known after apply) + policy = (known after apply) } } # aws_iam_role_policy_attachment.write_waf_logs will be created + resource "aws_iam_role_policy_attachment" "write_waf_logs" { + id = (known after apply) + policy_arn = (known after apply) + role = "url-shortener-waf-logs" } # aws_kinesis_firehose_delivery_stream.api will be created + resource "aws_kinesis_firehose_delivery_stream" "api" { + arn = (known after apply) + destination = "extended_s3" + destination_id = (known after apply) + id = (known after apply) + name = "aws-waf-logs-url-shortener" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + version_id = (known after apply) + extended_s3_configuration { + bucket_arn = "arn:aws:s3:::cbs-satellite-806721586252" + buffer_interval = 300 + buffer_size = 5 + compression_format = "GZIP" + prefix = "waf_acl_logs/AWSLogs/806721586252/" + role_arn = (known after apply) + s3_backup_mode = "Disabled" + cloudwatch_logging_options { + enabled = false } } + server_side_encryption { + enabled = true + key_type = "AWS_OWNED_CMK" } } # aws_route53_record.url_shortener_A will be created + resource "aws_route53_record" "url_shortener_A" { + allow_overwrite = (known after apply) + fqdn = (known after apply) + id = (known after apply) + name = "o.alpha.canada.ca" + type = "A" + zone_id = "Z0129461HK2TKOF3BTTF" + alias { + evaluate_target_health = false + name = (known after apply) + zone_id = (known after apply) } } # aws_route53_record.url_shortener_dns_validation["*.o.alpha.canada.ca"] will be created + resource "aws_route53_record" "url_shortener_dns_validation" { + allow_overwrite = true + fqdn = (known after apply) + id = (known after apply) + name = (known after apply) + records = (known after apply) + ttl = 60 + type = (known after apply) + zone_id = "Z0129461HK2TKOF3BTTF" } # aws_route53_record.url_shortener_dns_validation["o.alpha.canada.ca"] will be created + resource "aws_route53_record" "url_shortener_dns_validation" { + allow_overwrite = true + fqdn = (known after apply) + id = (known after apply) + name = (known after apply) + records = (known after apply) + ttl = 60 + type = (known after apply) + zone_id = "Z0129461HK2TKOF3BTTF" } # aws_wafv2_regex_pattern_set.login_uri_paths will be created + resource "aws_wafv2_regex_pattern_set" "login_uri_paths" { + arn = (known after apply) + description = "Regex to match the login paths of the API" + id = (known after apply) + lock_token = (known after apply) + name = "login-uri-paths" + scope = "CLOUDFRONT" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + regular_expression { + regex_string = "^/en/(login|magic-link)/?$" } + regular_expression { + regex_string = "^/fr/(connexion|lien-magique)/?$" } } # aws_wafv2_regex_pattern_set.valid_uri_paths will be created + resource "aws_wafv2_regex_pattern_set" "valid_uri_paths" { + arn = (known after apply) + description = "Regex to match the valid paths of hte API" + id = (known after apply) + lock_token = (known after apply) + name = "valid-api-paths" + scope = "CLOUDFRONT" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + regular_expression { + regex_string = "^/(version|healthcheck|openapi.json|.well-known/security.txt)$" } + regular_expression { + regex_string = "^/?(en|fr)?/?$" } + regular_expression { + regex_string = "^/[0-9A-Za-z]{8}/?$" } + regular_expression { + regex_string = "^/en/(login|logout|contact|magic-link)/?$" } + regular_expression { + regex_string = "^/fr/(connexion|deconnexion|contact|lien-magique)/?$" } + regular_expression { + regex_string = "^/lang/(en|fr)/?$" } + regular_expression { + regex_string = "^/static/(css|js|img)/[^/]+$" } + regular_expression { + regex_string = "^/v1/?$" } } # aws_wafv2_web_acl.api_waf will be created + resource "aws_wafv2_web_acl" "api_waf" { + arn = (known after apply) + capacity = (known after apply) + description = "WAF for URL shortener API" + id = (known after apply) + lock_token = (known after apply) + name = "url-shortener-waf" + scope = "CLOUDFRONT" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + custom_response_body { + content = jsonencode( { + detail = { + error = "Request blocked." + status = "ERROR" } } ) + content_type = "APPLICATION_JSON" + key = "json_request_blocked_error_response" } + custom_response_body { + content = jsonencode( { + detail = { + error = "Too many requests." + status = "ERROR" } } ) + content_type = "APPLICATION_JSON" + key = "json_request_rate_limited_error_response" } + default_action { + allow { } } + rule { + name = "APIInvalidPath" + priority = 5 + action { + block { + custom_response { + custom_response_body_key = "json_request_blocked_error_response" + response_code = 403 } } } + statement { + not_statement { + statement { + regex_pattern_set_reference_statement { + arn = (known after apply) + field_to_match { + uri_path {} } + text_transformation { + priority = 1 + type = "COMPRESS_WHITE_SPACE" } + text_transformation { + priority = 2 + type = "LOWERCASE" } } } } } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "APIInvalidPaths" + sampled_requests_enabled = true } } + rule { + name = "APIRateLimit" + priority = 20 + action { + block { + custom_response { + custom_response_body_key = "json_request_rate_limited_error_response" + response_code = 429 } } } + statement { + rate_based_statement { + aggregate_key_type = "IP" + limit = 2000 } } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "APIRateLimit" + sampled_requests_enabled = true } } + rule { + name = "LoginAPIRateLimit" + priority = 25 + action { + block { + custom_response { + custom_response_body_key = "json_request_rate_limited_error_response" + response_code = 429 } } } + statement { + rate_based_statement { + aggregate_key_type = "IP" + limit = 100 + scope_down_statement { + regex_pattern_set_reference_statement { + arn = (known after apply) + field_to_match { + uri_path {} } + text_transformation { + priority = 1 + type = "COMPRESS_WHITE_SPACE" } + text_transformation { + priority = 2 + type = "LOWERCASE" } } } } } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "LoginAPIRateLimit" + sampled_requests_enabled = true } } + rule { + name = "AWSManagedRulesAmazonIpReputationList" + priority = 10 + override_action { + none {} } + statement { + managed_rule_group_statement { + name = "AWSManagedRulesAmazonIpReputationList" + vendor_name = "AWS" } } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "AWSManagedRulesAmazonIpReputationList" + sampled_requests_enabled = true } } + rule { + name = "AWSManagedRulesCommonRuleSet" + priority = 30 + override_action { + none {} } + statement { + managed_rule_group_statement { + name = "AWSManagedRulesCommonRuleSet" + vendor_name = "AWS" } } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "AWSManagedRulesCommonRuleSet" + sampled_requests_enabled = true } } + rule { + name = "AWSManagedRulesKnownBadInputsRuleSet" + priority = 40 + override_action { + none {} } + statement { + managed_rule_group_statement { + name = "AWSManagedRulesKnownBadInputsRuleSet" + vendor_name = "AWS" } } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "AWSManagedRulesKnownBadInputsRuleSet" + sampled_requests_enabled = true } } + rule { + name = "AWSManagedRulesLinuxRuleSet" + priority = 50 + override_action { + none {} } + statement { + managed_rule_group_statement { + name = "AWSManagedRulesLinuxRuleSet" + vendor_name = "AWS" } } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "AWSManagedRulesLinuxRuleSet" + sampled_requests_enabled = true } } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "api" + sampled_requests_enabled = false } } # aws_wafv2_web_acl_logging_configuration.api will be created + resource "aws_wafv2_web_acl_logging_configuration" "api" { + id = (known after apply) + log_destination_configs = (known after apply) + resource_arn = (known after apply) } # module.resolver_dns.data.aws_iam_policy_document.route53_resolver_logging_policy will be read during apply # (config refers to values not yet known) <= data "aws_iam_policy_document" "route53_resolver_logging_policy" { + id = (known after apply) + json = (known after apply) + statement { + actions = [ + "logs:CreateLogStream", + "logs:PutLogEvents", ] + resources = [ + (known after apply), ] + principals { + identifiers = [ + "route53.amazonaws.com", ] + type = "Service" } } } # module.resolver_dns.aws_cloudwatch_log_group.route53_vpc_dns will be created + resource "aws_cloudwatch_log_group" "route53_vpc_dns" { + arn = (known after apply) + id = (known after apply) + name = "/aws/route53/url_shortener_vpc_id" + name_prefix = (known after apply) + retention_in_days = 30 + skip_destroy = false + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # module.resolver_dns.aws_cloudwatch_log_resource_policy.route53_vpc_dns will be created + resource "aws_cloudwatch_log_resource_policy" "route53_vpc_dns" { + id = (known after apply) + policy_document = (known after apply) + policy_name = "route53_resolver_logging_policy" } # module.resolver_dns.aws_route53_resolver_firewall_domain_list.allowed[0] will be created + resource "aws_route53_resolver_firewall_domain_list" "allowed" { + arn = (known after apply) + domains = [ + "*.akamaiedge.net.", + "*.amazonaws.com.", + "*.canada.ca.", + "*.edgekey.net.", + "*.gc.ca.", + "*.gg.ca.", + "canada.ca.", + "gg.ca.", ] + id = (known after apply) + name = "AllowedDomains" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # module.resolver_dns.aws_route53_resolver_firewall_domain_list.blocked[0] will be created + resource "aws_route53_resolver_firewall_domain_list" "blocked" { + arn = (known after apply) + domains = [ + "*.", ] + id = (known after apply) + name = "BlockedDomains" + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # module.resolver_dns.aws_route53_resolver_firewall_rule.allowed[0] will be created + resource "aws_route53_resolver_firewall_rule" "allowed" { + action = "ALLOW" + firewall_domain_list_id = (known after apply) + firewall_rule_group_id = (known after apply) + id = (known after apply) + name = "AllowedDomains" + priority = 100 } # module.resolver_dns.aws_route53_resolver_firewall_rule.blocked[0] will be created + resource "aws_route53_resolver_firewall_rule" "blocked" { + action = "BLOCK" + block_response = "NODATA" + firewall_domain_list_id = (known after apply) + firewall_rule_group_id = (known after apply) + id = (known after apply) + name = "BlockedDomains" + priority = 200 } # module.resolver_dns.aws_route53_resolver_firewall_rule_group.firewall_rules[0] will be created + resource "aws_route53_resolver_firewall_rule_group" "firewall_rules" { + arn = (known after apply) + id = (known after apply) + name = "FirewallRules" + owner_id = (known after apply) + share_status = (known after apply) + tags = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } + tags_all = { + "CostCentre" = "url-shortener-production" + "Terraform" = "true" } } # module.resolver_dns.aws_route53_resolver_firewall_rule_group_association.firewall_rules[0] will be created + resource "aws_route53_resolver_firewall_rule_group_association" "firewall_rules" { + arn = (known after apply) + firewall_rule_group_id = (known after apply) + id = (known after apply) + mutation_protection = (known after apply) + name = "FirewallRules" + priority = 101 + tags_all = (known after apply) + vpc_id ... ```
Show Conftest results ```sh WARN - plan.json - main - Missing Common Tags: ["module.resolver_dns.aws_route53_resolver_firewall_rule_group_association.firewall_rules[0]"] WARN - plan.json - main - Missing Common Tags: ["module.resolver_dns.aws_route53_resolver_query_log_config.route53_vpc_dns"] 19 tests, 17 passed, 2 warnings, 0 failures, 0 exceptions ```