Hi , I’m running a terraform plan and want to ensure that only certain IAM users/roles are allowed to do a terraform apply on certain resources.
I’m trying to figure out where does terraform store the information regarding who is creating these resources and can we block if the user/role doesn’t match in the opa policy we defined ?
Below is the opa policy that i’ve in place , this is checking for aws resources and only if the request is from certain users/roles then it should pass, in this policy i’m checking prior_state , but this configuration block isn’t present in all terraform plan (json file)
package terraform.network
import future.keywords
import input.plan
resources_to_check := [
"aws_ec2_transit_gateway_peering_attachment_accepter",
"aws_ec2_transit_gateway_route",
"aws_ec2_transit_gateway_route_table_association",
"aws_ec2_transit_gateway_peering_attachment",
"aws_ssm_parameter",
"aws_ec2_transit_gateway",
"aws_iam_policy",
"aws_vpc"
]
allowed_roles := ["AWSCloudFormationStackSetExecutionRole", "AWSReservedSSO_AdministratorAccess_"]
array_contains(arr, elem) if {
arr[_] = elem
}
# allowed_actions := {"create", "update"}
deny contains msg if {
r := plan.resource_changes[_]
action := r.change.actions[count(r.change.actions) - 1]
array_contains(["create", "update"], action)
not array_contains(resources_to_check, r.type)
ar := input.prior_state.values.root_module.child_modules[_].resources[_]
roles := ar.values.arn
roles
role_split := split(roles, "/")
some ro in allowed_roles
role := role_split[1]
not startswith(role, ro)
msg := sprintf("Resource: %s can not be created/updated with %s role.", [r.type, role])
}
this is the sample terraform out json file
{
"format_version":"1.2",
"terraform_version":"1.5.2",
"planned_values":{
"root_module":{
"resources":[
{
"address":"aws_iam_policy.policy",
"mode":"managed",
"type":"aws_iam_policy",
"name":"policy",
"provider_name":"registry.terraform.io/hashicorp/aws",
"schema_version":0,
"values":{
"description":"My test policy",
"name":"test_policy",
"path":"/",
"policy":"{\"Statement\":[{\"Action\":[\"ec2:Describe*\"],\"Effect\":\"Allow\",\"Resource\":\"*\"}],\"Version\":\"2012-10-17\"}",
"tags":null
},
"sensitive_values":{
"tags_all":{
}
}
},
{
"address":"aws_s3_bucket.b",
"mode":"managed",
"type":"aws_s3_bucket",
"name":"b",
"provider_name":"registry.terraform.io/hashicorp/aws",
"schema_version":0,
"values":{
"acl":"private",
"bucket":"my-tf-test-bucket",
"force_destroy":false,
"tags":{
"Environment":"Dev",
"Name":"My bucket"
},
"tags_all":{
"Environment":"Dev",
"Name":"My bucket"
},
"timeouts":null
},
"sensitive_values":{
"cors_rule":[
],
"grant":[
],
"lifecycle_rule":[
],
"logging":[
],
"object_lock_configuration":[
],
"replication_configuration":[
],
"server_side_encryption_configuration":[
],
"tags":{
},
"tags_all":{
},
"versioning":[
],
"website":[
]
}
}
]
}
},
"resource_changes":[
{
"address":"aws_iam_policy.policy",
"mode":"managed",
"type":"aws_iam_policy",
"name":"policy",
"provider_name":"registry.terraform.io/hashicorp/aws",
"change":{
"actions":[
"create"
],
"before":null,
"after":{
"description":"My test policy",
"name":"test_policy",
"path":"/",
"policy":"{\"Statement\":[{\"Action\":[\"ec2:Describe*\"],\"Effect\":\"Allow\",\"Resource\":\"*\"}],\"Version\":\"2012-10-17\"}",
"tags":null
},
"after_unknown":{
"arn":true,
"id":true,
"name_prefix":true,
"policy_id":true,
"tags_all":true
},
"before_sensitive":false,
"after_sensitive":{
"tags_all":{
}
}
}
},
{
"address":"aws_s3_bucket.b",
"mode":"managed",
"type":"aws_s3_bucket",
"name":"b",
"provider_name":"registry.terraform.io/hashicorp/aws",
"change":{
"actions":[
"create"
],
"before":null,
"after":{
"acl":"private",
"bucket":"my-tf-test-bucket",
"force_destroy":false,
"tags":{
"Environment":"Dev",
"Name":"My bucket"
},
"tags_all":{
"Environment":"Dev",
"Name":"My bucket"
},
"timeouts":null
},
"after_unknown":{
"acceleration_status":true,
"arn":true,
"bucket_domain_name":true,
"bucket_prefix":true,
"bucket_regional_domain_name":true,
"cors_rule":true,
"grant":true,
"hosted_zone_id":true,
"id":true,
"lifecycle_rule":true,
"logging":true,
"object_lock_configuration":true,
"object_lock_enabled":true,
"policy":true,
"region":true,
"replication_configuration":true,
"request_payer":true,
"server_side_encryption_configuration":true,
"tags":{
},
"tags_all":{
},
"versioning":true,
"website":true,
"website_domain":true,
"website_endpoint":true
},
"before_sensitive":false,
"after_sensitive":{
"cors_rule":[
],
"grant":[
],
"lifecycle_rule":[
],
"logging":[
],
"object_lock_configuration":[
],
"replication_configuration":[
],
"server_side_encryption_configuration":[
],
"tags":{
},
"tags_all":{
},
"versioning":[
],
"website":[
]
}
}
}
],
"configuration":{
"provider_config":{
"aws":{
"name":"aws",
"full_name":"registry.terraform.io/hashicorp/aws",
"expressions":{
"access_key":{
"constant_value":"AKIA3REMOVED"
},
"region":{
"constant_value":"ap-south-1"
},
"secret_key":{
"constant_value":"wq5of/I+M3euRglREMOVED"
}
}
}
},
"root_module":{
"resources":[
{
"address":"aws_iam_policy.policy",
"mode":"managed",
"type":"aws_iam_policy",
"name":"policy",
"provider_config_key":"aws",
"expressions":{
"description":{
"constant_value":"My test policy"
},
"name":{
"constant_value":"test_policy"
},
"path":{
"constant_value":"/"
},
"policy":{
}
},
"schema_version":0
},
{
"address":"aws_s3_bucket.b",
"mode":"managed",
"type":"aws_s3_bucket",
"name":"b",
"provider_config_key":"aws",
"expressions":{
"acl":{
"constant_value":"private"
},
"bucket":{
"constant_value":"my-tf-test-bucket"
},
"tags":{
"constant_value":{
"Environment":"Dev",
"Name":"My bucket"
}
}
},
"schema_version":0
}
]
}
},
"timestamp":"2023-07-11T08:05:04Z"
}```