Skip to content

Instantly share code, notes, and snippets.

@danielvrog
Last active February 25, 2024 21:29
Show Gist options
  • Save danielvrog/e1549f9b7504a2421fc496aa4d43abb6 to your computer and use it in GitHub Desktop.
Save danielvrog/e1549f9b7504a2421fc496aa4d43abb6 to your computer and use it in GitHub Desktop.
OPA Conftest: Validate all AWS resources are tagged in your Terraform code
#!/bin/bash
# In ordet to update the list of taggable resources:
git clone https://github.com/hashicorp/terraform-provider-aws.git
cd terraform-provider-aws/website/docs/r
grep -l "\`tags\`" *.html.markdown | awk -F'.' '$0="aws_"$1' | jq --raw-input . | jq --slurp .
package tag
deny[msg] {
some resource
isTaggableResource[resource]
not hasTags[resource]
resource_changes_address := input.resource_changes[resource].address
msg := sprintf("Resource '%s' must be tagged!", [resource_changes_address])
}
isTaggableResource[resource] {
resource_changes_type := input.resource_changes[resource].type
taggable_resource_types[_] == resource_changes_type
}
hasTags[resource] {
input.resource_changes[resource].change.after.tags
}
# In ordet to update the list of taggable resources:
# git clone https://github.com/hashicorp/terraform-provider-aws.git
# cd terraform-provider-aws/website/docs/r
# grep -l "\`tags\`" *.html.markdown | awk -F'.' '$0="aws_"$1' | jq --raw-input . | jq --slurp .
taggable_resource_types = {
"aws_accessanalyzer_analyzer",
"aws_acm_certificate",
"aws_acmpca_certificate_authority",
"aws_ami",
"aws_ami_copy",
"aws_ami_from_instance",
"aws_amplify_app",
"aws_amplify_branch",
"aws_api_gateway_api_key",
"aws_api_gateway_client_certificate",
"aws_api_gateway_domain_name",
"aws_api_gateway_rest_api",
"aws_api_gateway_stage",
"aws_api_gateway_usage_plan",
"aws_api_gateway_vpc_link",
"aws_apigatewayv2_api",
"aws_apigatewayv2_domain_name",
"aws_apigatewayv2_stage",
"aws_apigatewayv2_vpc_link",
"aws_appmesh_gateway_route",
"aws_appmesh_mesh",
"aws_appmesh_route",
"aws_appmesh_virtual_gateway",
"aws_appmesh_virtual_node",
"aws_appmesh_virtual_router",
"aws_appmesh_virtual_service",
"aws_apprunner_auto_scaling_configuration_version",
"aws_apprunner_connection",
"aws_apprunner_service",
"aws_appsync_graphql_api",
"aws_athena_workgroup",
"aws_autoscaling_group",
"aws_backup_plan",
"aws_backup_vault",
"aws_batch_compute_environment",
"aws_batch_job_definition",
"aws_batch_job_queue",
"aws_cloud9_environment_ec2",
"aws_cloudformation_stack",
"aws_cloudformation_stack_set",
"aws_cloudfront_distribution",
"aws_cloudhsm_v2_cluster",
"aws_cloudtrail",
"aws_cloudwatch_composite_alarm",
"aws_cloudwatch_event_bus",
"aws_cloudwatch_event_rule",
"aws_cloudwatch_log_group",
"aws_cloudwatch_metric_alarm",
"aws_cloudwatch_metric_stream",
"aws_codeartifact_domain",
"aws_codeartifact_repository",
"aws_codebuild_project",
"aws_codebuild_report_group",
"aws_codecommit_repository",
"aws_codedeploy_app",
"aws_codedeploy_deployment_group",
"aws_config_config_rule",
"aws_config_configuration_aggregator",
"aws_customer_gateway",
"aws_datapipeline_pipeline",
"aws_datasync_agent",
"aws_datasync_location_efs",
"aws_datasync_location_fsx_windows_file_system",
"aws_datasync_location_nfs",
"aws_datasync_location_s3",
"aws_datasync_location_smb",
"aws_datasync_task",
"aws_dax_cluster",
"aws_db_cluster_snapshot",
"aws_db_event_subscription",
"aws_db_instance",
"aws_db_option_group",
"aws_db_parameter_group",
"aws_db_proxy",
"aws_db_proxy_endpoint",
"aws_db_security_group",
"aws_db_snapshot",
"aws_db_subnet_group",
"aws_default_network_acl",
"aws_default_route_table",
"aws_default_security_group",
"aws_default_subnet",
"aws_default_vpc",
"aws_default_vpc_dhcp_options",
"aws_devicefarm_project",
"aws_directory_service_directory",
"aws_dms_certificate",
"aws_dms_endpoint",
"aws_dms_event_subscription",
"aws_dms_replication_instance",
"aws_dms_replication_subnet_group",
"aws_dms_replication_task",
"aws_docdb_cluster",
"aws_docdb_cluster_instance",
"aws_docdb_cluster_parameter_group",
"aws_docdb_subnet_group",
"aws_dx_connection",
"aws_dx_hosted_private_virtual_interface_accepter",
"aws_dx_hosted_public_virtual_interface_accepter",
"aws_dx_hosted_transit_virtual_interface_accepter",
"aws_dx_lag",
"aws_dx_private_virtual_interface",
"aws_dx_public_virtual_interface",
"aws_dx_transit_virtual_interface",
"aws_dynamodb_table",
"aws_ebs_snapshot",
"aws_ebs_snapshot_copy",
"aws_ebs_volume",
"aws_ec2_capacity_reservation",
"aws_ec2_carrier_gateway",
"aws_ec2_client_vpn_endpoint",
"aws_ec2_fleet",
"aws_ec2_local_gateway_route_table_vpc_association",
"aws_ec2_managed_prefix_list",
"aws_ec2_traffic_mirror_filter",
"aws_ec2_traffic_mirror_session",
"aws_ec2_traffic_mirror_target",
"aws_ec2_transit_gateway",
"aws_ec2_transit_gateway_peering_attachment",
"aws_ec2_transit_gateway_peering_attachment_accepter",
"aws_ec2_transit_gateway_route_table",
"aws_ec2_transit_gateway_vpc_attachment",
"aws_ec2_transit_gateway_vpc_attachment_accepter",
"aws_ecr_repository",
"aws_ecs_capacity_provider",
"aws_ecs_cluster",
"aws_ecs_service",
"aws_ecs_task_definition",
"aws_efs_access_point",
"aws_efs_file_system",
"aws_egress_only_internet_gateway",
"aws_eip",
"aws_eks_addon",
"aws_eks_cluster",
"aws_eks_fargate_profile",
"aws_eks_node_group",
"aws_elastic_beanstalk_application",
"aws_elastic_beanstalk_application_version",
"aws_elastic_beanstalk_environment",
"aws_elasticache_cluster",
"aws_elasticache_parameter_group",
"aws_elasticache_replication_group",
"aws_elasticache_subnet_group",
"aws_elasticsearch_domain",
"aws_elb",
"aws_emr_cluster",
"aws_flow_log",
"aws_fsx_lustre_file_system",
"aws_fsx_windows_file_system",
"aws_gamelift_alias",
"aws_gamelift_build",
"aws_gamelift_fleet",
"aws_gamelift_game_session_queue",
"aws_glacier_vault",
"aws_glue_crawler",
"aws_glue_job",
"aws_glue_ml_transform",
"aws_glue_registry",
"aws_glue_schema",
"aws_glue_trigger",
"aws_glue_workflow",
"aws_guardduty_detector",
"aws_guardduty_filter",
"aws_guardduty_ipset",
"aws_guardduty_threatintelset",
"aws_iam_instance_profile",
"aws_iam_openid_connect_provider",
"aws_iam_policy",
"aws_iam_role",
"aws_iam_saml_provider",
"aws_iam_server_certificate",
"aws_iam_user",
"aws_imagebuilder_component",
"aws_imagebuilder_distribution_configuration",
"aws_imagebuilder_image",
"aws_imagebuilder_image_pipeline",
"aws_imagebuilder_image_recipe",
"aws_imagebuilder_infrastructure_configuration",
"aws_inspector_assessment_template",
"aws_inspector_resource_group",
"aws_instance",
"aws_internet_gateway",
"aws_iot_topic_rule",
"aws_key_pair",
"aws_kinesis_analytics_application",
"aws_kinesis_firehose_delivery_stream",
"aws_kinesis_stream",
"aws_kinesis_video_stream",
"aws_kinesisanalyticsv2_application",
"aws_kms_external_key",
"aws_kms_key",
"aws_lambda_function",
"aws_launch_template",
"aws_lb",
"aws_lb_listener",
"aws_lb_listener_rule",
"aws_lb_target_group",
"aws_lightsail_instance",
"aws_macie2_classification_job",
"aws_macie2_custom_data_identifier",
"aws_macie2_findings_filter",
"aws_macie2_member",
"aws_media_convert_queue",
"aws_media_package_channel",
"aws_media_store_container",
"aws_mq_broker",
"aws_mq_configuration",
"aws_msk_cluster",
"aws_mwaa_environment",
"aws_nat_gateway",
"aws_neptune_cluster",
"aws_neptune_cluster_instance",
"aws_neptune_cluster_parameter_group",
"aws_neptune_event_subscription",
"aws_neptune_parameter_group",
"aws_neptune_subnet_group",
"aws_network_acl",
"aws_networkfirewall_firewall",
"aws_networkfirewall_firewall_policy",
"aws_networkfirewall_rule_group",
"aws_opsworks_custom_layer",
"aws_opsworks_ganglia_layer",
"aws_opsworks_haproxy_layer",
"aws_opsworks_java_app_layer",
"aws_opsworks_memcached_layer",
"aws_opsworks_mysql_layer",
"aws_opsworks_nodejs_app_layer",
"aws_opsworks_php_app_layer",
"aws_opsworks_rails_app_layer",
"aws_opsworks_stack",
"aws_opsworks_static_web_layer",
"aws_organizations_account",
"aws_organizations_organizational_unit",
"aws_organizations_policy",
"aws_placement_group",
"aws_qldb_ledger",
"aws_rds_cluster",
"aws_rds_cluster_endpoint",
"aws_rds_cluster_instance",
"aws_redshift_cluster",
"aws_redshift_event_subscription",
"aws_redshift_parameter_group",
"aws_redshift_snapshot_copy_grant",
"aws_redshift_snapshot_schedule",
"aws_redshift_subnet_group",
"aws_resourcegroups_group",
"aws_route53_health_check",
"aws_route53_resolver_endpoint",
"aws_route53_resolver_query_log_config",
"aws_route53_resolver_rule",
"aws_route53_zone",
"aws_route_table",
"aws_s3_bucket",
"aws_s3_bucket_analytics_configuration",
"aws_s3_bucket_metric",
"aws_s3_bucket_object",
"aws_s3_object_copy",
"aws_s3control_bucket",
"aws_s3control_bucket_lifecycle_configuration",
"aws_sagemaker_app",
"aws_sagemaker_domain",
"aws_sagemaker_endpoint",
"aws_sagemaker_endpoint_configuration",
"aws_sagemaker_feature_group",
"aws_sagemaker_image",
"aws_sagemaker_model",
"aws_sagemaker_model_package_group",
"aws_sagemaker_notebook_instance",
"aws_sagemaker_user_profile",
"aws_schemas_discoverer",
"aws_schemas_registry",
"aws_schemas_schema",
"aws_secretsmanager_secret",
"aws_security_group",
"aws_serverlessapplicationrepository_cloudformation_stack",
"aws_service_discovery_http_namespace",
"aws_service_discovery_private_dns_namespace",
"aws_service_discovery_public_dns_namespace",
"aws_service_discovery_service",
"aws_servicecatalog_portfolio",
"aws_servicecatalog_product",
"aws_sfn_activity",
"aws_sfn_state_machine",
"aws_shield_protection",
"aws_signer_signing_profile",
"aws_sns_topic",
"aws_spot_fleet_request",
"aws_spot_instance_request",
"aws_sqs_queue",
"aws_ssm_activation",
"aws_ssm_document",
"aws_ssm_maintenance_window",
"aws_ssm_parameter",
"aws_ssm_patch_baseline",
"aws_ssoadmin_permission_set",
"aws_storagegateway_cached_iscsi_volume",
"aws_storagegateway_gateway",
"aws_storagegateway_nfs_file_share",
"aws_storagegateway_smb_file_share",
"aws_storagegateway_stored_iscsi_volume",
"aws_storagegateway_tape_pool",
"aws_subnet",
"aws_swf_domain",
"aws_synthetics_canary",
"aws_timestreamwrite_database",
"aws_timestreamwrite_table",
"aws_transfer_server",
"aws_transfer_user",
"aws_vpc",
"aws_vpc_dhcp_options",
"aws_vpc_endpoint",
"aws_vpc_endpoint_service",
"aws_vpc_peering_connection",
"aws_vpc_peering_connection_accepter",
"aws_vpn_connection",
"aws_vpn_gateway",
"aws_waf_rate_based_rule",
"aws_waf_rule",
"aws_waf_rule_group",
"aws_waf_web_acl",
"aws_wafregional_rate_based_rule",
"aws_wafregional_rule",
"aws_wafregional_rule_group",
"aws_wafregional_web_acl",
"aws_wafv2_ip_set",
"aws_wafv2_regex_pattern_set",
"aws_wafv2_rule_group",
"aws_wafv2_web_acl",
"aws_workspaces_directory",
"aws_workspaces_ip_group",
"aws_workspaces_workspace",
"aws_xray_group",
"aws_xray_sampling_rule"
}
package tag
test_empty_input {
deny with input as {}
}
test_taggable_resource_not_tagged {
deny with input as {"resource_changes": [{
"address": "aws_s3_bucket.test_aws_s3_bucket",
"type": "aws_s3_bucket",
"name": "test_aws_s3_bucket",
"change": {"after": {}},
}]}
}
test_taggable_resource_tagged {
not deny[""] with input as {"resource_changes": [{
"address": "aws_s3_bucket.test_aws_s3_bucket",
"type": "aws_s3_bucket",
"name": "test_aws_s3_bucket",
"change": {"after": {"tags": {"key": "val"}}},
}]}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment