terraform-provider-aws: aws_codepipeline with Github OAuth causing persistent changes
Terraform Version
Terraform v0.11.1 Terraform AWS Provider v1.6.0
Affected Resource(s)
Please list the resources as a list, for example:
aws_codepipeline
Terraform Configuration Files
resource "aws_codepipeline" "build" {
name = "pipeline-test"
role_arn = "pipeline-test"
artifact_store {
type = "S3"
location = "pipeline-test-bucket"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "ThirdParty"
provider = "GitHub"
version = "1"
output_artifacts = ["code"]
configuration {
OAuthToken = "${var.github_token}"
Owner = "${var.github_owner}"
Repo = "${var.github_repo}"
Branch = "${var.github_branch}"
PollForSourceChanges = "true"
}
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["code"]
output_artifacts = ["package"]
configuration {
ProjectName = "${var.project_name}"
}
}
}
}
Expected Behavior
Subsequent executions of terraform apply should not result in updates to the source attributes.
Actual Behavior
Running terraform plan/terraform apply always results in a change:
~ aws_codepipeline.build
stage.0.action.0.configuration.%: "4" => "5"
stage.0.action.0.configuration.OAuthToken: "" => "REDACTED"
And AWS is incapable of accessing Github, even though the token is valid, tested, and with the correct scopes.
Steps to Reproduce
Please list the steps required to reproduce the issue, for example:
terraform planterraform applyterraform apply
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 52
- Comments: 21 (5 by maintainers)
I had a look at the provider code and it seems that the
OAuthTokenis getting deleted from the state file.I suspect this has been done to not store secrets in state file. However, in other resources like
aws_db_instance, we store the passwords in state file. The state file always has been the single source of truth. The issue pointed out here violates that principal and kind of degrades the developer experience.I suggest we change this behaviour and store the token in the state file and keep the experience consistent across resource.
Moreover, the
OAuthTokenvalue is taken from an environment variable, which is again not consistent with other resources.I’m experiencing the same issue, but managed to work around it by adding the following to my
aws_codepipelineresource:The GitHub token isn’t likely to change often in my use case, so the inconvenience of having to remove & restore that
lifecycleblock is not a big deal compared to having to confirm that I want to “change” the token on every single run (and having it displayed on the screen in plaintext each time, too).It doesn’t address the root cause, but hopefully someone else will find this workaround useful.
EDIT (2019-05-09): See my updated workaround below if you’re experiencing this problem with Terraform
0.12.0-rc1or newer.I was able to get as far as:
ignore_changes = [stage[0].action[0].configuration]However, I couldn’t figure out how to specifically ignore one attribute of
configurationsuch asOAuthTokeneither.Ignoring the entire configuration won’t work for my use case.
Even when I specify the
GITHUB_TOKENenvironment variable I still get the same issue as the OP. Is there something else you need to do as well?Update for
0.12.0-rc1:This is still broken in
0.12.0-rc1, but the workaround I posted a year ago (hacky birthday! 🎂) doesn’t work anymore.You’ll first see an error saying “
Dot must be followed by attribute name”, which can be fixed by usingstage[0].action[0]instead ofstage.0.action.0. That will fix the.OAuthTokenportion, but the.configuration.%portion will not work. I also tried.configuration[%]and even tried incorporating the splat operator, but no dice there (“Splat expressions (.*) may not be used here.”).The following approach will work in
0.12:NOTE: You could technically use
ignore_changes = [stage]as well, which will allow you to update the CodePipeline resource itself as long as you don’t modify the stages. I prefer theallapproach, because it will make it more obvious that something is wrong if I try to modify the resource itself and the stages. Using[stage]would allow top-level attribute changes to take place, while ignoring the changes to thestageblock, which could lead to unpredictable results and an all-around bad time.@bflad @gdavison (please forward if someone else should be looking at the CodePipeline provider).
In the worst case, a hash of the OAuthToken could be stored in the state file so that we can do change-detection without having to expose the actual secret.
@sunilkumarmohanty if that is the case, then let’s just store the asterisk and move on. Who cares if it’s not an absolute truth, as long as it stops breaking expectations.
On further debugging, I found that the
GetPipelinemethod ofaws sdk for goreturns **** instead of the actualOAuthToken, which means that the state file will always have **** in it instead of the actualOAuthToken. Hence, every timeterraform planis run, it will always state that the pipeline needs modification.The solution proposed by @michaelmoussa is good, but it is not applicable when you are using the module which, in turn, creates the
aws_codepipelineresource.It is very inconvenient to change the source code of that module to comment/uncomment
lifecycleblock all the time (if you have a group of infrastructure engineers). And downright impossible if you have it published in GitHub.Another solution is to use conditional resources i.e.
count={var.force_github_token ? 1 : 0}but the problem is I already have 6 different codepipeline resources and that, in turn, will lead to having 12 codepipeline resources.