Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/resolve single depth references #8

Merged
merged 3 commits into from
Feb 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions terraform_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,20 @@ type TerraformPlanResourceChange struct {
Before map[string]interface{} // will be null when the action is `create`
After map[string]interface{} // will be null when then action is `delete`
}
Expressions interface{} `json:"expressions"`
}

type TerraformPlanModule struct {
Resources []TerraformPlanResourceChange `json:"resources"`
}

type TerraformPlanConfiguration struct {
RootModule TerraformPlanModule `json:"root_module"`
}

type TerraformPlanJson struct {
ResourceChanges []TerraformPlanResourceChange `json:"resource_changes"`
Configuration TerraformPlanConfiguration `json:"configuration"`
}

type TerraformScanInput map[string]map[string]map[string]interface{}
Expand Down Expand Up @@ -72,9 +82,66 @@ func parseTerraformPlan(planJson TerraformPlanJson, isFullScan bool) TerraformSc
}
}
}

// check root module for references in first depth of attributes
for _, resource := range planJson.Configuration.RootModule.Resources {
// don't care about references in data sources for time being
if resource.Mode == "data" {
continue
}
mode := "resource"
// only update the references in resources that have some resolved attributes already
if resolvedResource, ok := scanInput[mode][resource.Type][getResourceName(resource)].(map[string]interface{}); ok {
expressions := getExpressions(resource.Expressions)
for k, v := range expressions {
// only add non existing attributes. If we already have resolved value do not overwrite it with reference
if _, ok := resolvedResource[k]; !ok {
resolvedResource[k] = v
}
}
scanInput[mode][resource.Type][getResourceName(resource)] = resolvedResource
}
}

return scanInput
}

func getExpressions(expressions interface{}) map[string]interface{} {
result := make(map[string]interface{})
// expressions can be nested. we are only doing 1 depth to resolve top level depenencies
expressionMap, ok := expressions.(map[string]interface{})
if !ok {
return nil
}
for k, v := range expressionMap {
referenceKey, ok := getReference(v)
if ok {
result[k] = referenceKey
}
}
return result
}

// this is very naive implementation
// the referenences can be composed of number of keys
// we only going to use the first reference for time being
func getReference(value interface{}) (interface{}, bool) {
v, ok := value.(map[string]interface{})
if !ok {
return "", false
}
// we are only interested with "references" values
referencesInt, ok := v["references"]
if !ok {
return "", false
}
references, ok := referencesInt.([]interface{})
if !ok {
return "", false
}
return references[0], true
}

func getResourceName(resource TerraformPlanResourceChange) string {
if resource.Index == nil {
return resource.Name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
],
"source_version": null,
"tags": null,
"vpc_config": []
"vpc_config": [],
"service_role": "aws_iam_role.terra_ci_job"
}
},
"aws_iam_role": {
Expand Down Expand Up @@ -97,11 +98,13 @@
"aws_iam_role_policy": {
"terra_ci_job": {
"name_prefix": null,
"role": "terra_ci_job"
"role": "terra_ci_job",
"policy": "data.aws_caller_identity.current"
},
"terra_ci_runner": {
"name_prefix": null,
"role": "terra_ci_runner"
"role": "terra_ci_runner",
"policy": "aws_codebuild_project.terra_ci"
}
},
"aws_iam_role_policy_attachment": {
Expand Down Expand Up @@ -147,7 +150,8 @@
"definition": "{\n \"Comment\": \"Run Terragrunt Jobs\",\n \"StartAt\": \"OnBranch?\",\n \"States\": {\n \"OnBranch?\": {\n \"Type\": \"Choice\",\n \"Choices\": [\n {\n \"Variable\": \"$.build.sourceversion\",\n \"IsPresent\": true,\n \"Next\": \"PlanBranch\"\n }\n ],\n \"Default\": \"Plan\"\n },\n \"Plan\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:states:::codebuild:startBuild.sync\",\n \"Parameters\": {\n \"ProjectName\": \"terra-ci-runner\",\n \"EnvironmentVariablesOverride\": [\n {\n \"Name\": \"TERRA_CI_BUILD_NAME\",\n \"Value.$\": \"$$.Execution.Name\"\n },\n {\n \"Name\": \"TERRA_CI_RESOURCE\",\n \"Value.$\": \"$.build.environment.terra_ci_resource\"\n }\n ]\n },\n \"End\": true\n },\n \"PlanBranch\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:states:::codebuild:startBuild.sync\",\n \"Parameters\": {\n \"ProjectName\": \"terra-ci-runner\",\n \"SourceVersion.$\": \"$.build.sourceversion\",\n \"EnvironmentVariablesOverride\": [\n {\n \"Name\": \"TERRA_CI_RESOURCE\",\n \"Value.$\": \"$.build.environment.terra_ci_resource\"\n }\n ]\n },\n \"End\": true\n }\n }\n}\n",
"name": "terra-ci-runner",
"tags": null,
"type": "STANDARD"
"type": "STANDARD",
"role_arn": "aws_iam_role.terra_ci_runner"
}
},
"aws_route": {
Expand Down Expand Up @@ -184,4 +188,4 @@
}
},
"data": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"data": {},
"resource": {
"aws_s3_bucket": {
"denied": {
"bucket": "denied",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
},
"duh": {
"bucket": "duh",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
},
"logging2": {
"bucket": "logging2",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
}
},
"aws_s3_bucket_logging": {
"example": {
"bucket": "aws_s3_bucket.logging2.id",
"target_bucket": "aws_s3_bucket.duh.id",
"expected_bucket_owner": null,
"target_grant": [],
"target_prefix": "log/"
},
"example2": {
"bucket": "aws_s3_bucket.logging2.id",
"target_bucket": "aws_s3_bucket.duh.id",
"expected_bucket_owner": null,
"target_grant": [],
"target_prefix": "log/"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
],
"source_version": null,
"tags": null,
"vpc_config": []
"vpc_config": [],
"service_role": "aws_iam_role.terra_ci_job"
}
},
"aws_iam_role": {
Expand Down Expand Up @@ -97,11 +98,13 @@
"aws_iam_role_policy": {
"terra_ci_job": {
"name_prefix": null,
"role": "terra_ci_job"
"role": "terra_ci_job",
"policy": "data.aws_caller_identity.current"
},
"terra_ci_runner": {
"name_prefix": null,
"role": "terra_ci_runner"
"role": "terra_ci_runner",
"policy": "aws_codebuild_project.terra_ci"
}
},
"aws_iam_role_policy_attachment": {
Expand Down Expand Up @@ -147,7 +150,8 @@
"definition": "{\n \"Comment\": \"Run Terragrunt Jobs\",\n \"StartAt\": \"OnBranch?\",\n \"States\": {\n \"OnBranch?\": {\n \"Type\": \"Choice\",\n \"Choices\": [\n {\n \"Variable\": \"$.build.sourceversion\",\n \"IsPresent\": true,\n \"Next\": \"PlanBranch\"\n }\n ],\n \"Default\": \"Plan\"\n },\n \"Plan\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:states:::codebuild:startBuild.sync\",\n \"Parameters\": {\n \"ProjectName\": \"terra-ci-runner\",\n \"EnvironmentVariablesOverride\": [\n {\n \"Name\": \"TERRA_CI_BUILD_NAME\",\n \"Value.$\": \"$$.Execution.Name\"\n },\n {\n \"Name\": \"TERRA_CI_RESOURCE\",\n \"Value.$\": \"$.build.environment.terra_ci_resource\"\n }\n ]\n },\n \"End\": true\n },\n \"PlanBranch\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:states:::codebuild:startBuild.sync\",\n \"Parameters\": {\n \"ProjectName\": \"terra-ci-runner\",\n \"SourceVersion.$\": \"$.build.sourceversion\",\n \"EnvironmentVariablesOverride\": [\n {\n \"Name\": \"TERRA_CI_RESOURCE\",\n \"Value.$\": \"$.build.environment.terra_ci_resource\"\n }\n ]\n },\n \"End\": true\n }\n }\n}\n",
"name": "terra-ci-runner",
"tags": null,
"type": "STANDARD"
"type": "STANDARD",
"role_arn": "aws_iam_role.terra_ci_runner"
}
},
"aws_route": {
Expand Down Expand Up @@ -184,4 +188,4 @@
}
},
"data": {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"resource": {
"aws_codebuild_project": {
"terra_ci": {
"service_role": "aws_iam_role.terra_ci_job",
"arn": "arn:aws:codebuild:eu-west-1:719261439472:project/terra-ci-runner",
"artifacts": [
{
Expand Down Expand Up @@ -222,4 +223,4 @@
}
},
"data": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"data": {},
"resource": {
"aws_s3_bucket": {
"denied": {
"bucket": "denied",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
},
"duh": {
"bucket": "duh",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
},
"logging2": {
"bucket": "logging2",
"bucket_prefix": null,
"force_destroy": false,
"tags": null
}
},
"aws_s3_bucket_logging": {
"example": {
"bucket": "aws_s3_bucket.logging2.id",
"target_bucket": "aws_s3_bucket.duh.id",
"expected_bucket_owner": null,
"target_grant": [],
"target_prefix": "log/"
},
"example2": {
"bucket": "aws_s3_bucket.logging2.id",
"target_bucket": "aws_s3_bucket.duh.id",
"expected_bucket_owner": null,
"target_grant": [],
"target_prefix": "log/"
}
}
}
}
Loading