pipeline-aws-plugin icon indicating copy to clipboard operation
pipeline-aws-plugin copied to clipboard

withAWS() puts secret key into Jenkins log file if env vars are printed...

Open mattemoore opened this issue 6 years ago • 9 comments

Description

Secret key is readable in the Jenkins pipeline log file.

Steps to Reproduce

  1. In your pipeline use withAWS in option block of declarative pipeline:

def AWS_ROLE = "arn:aws:iam::321724181329:role/QEAutomation" // AWS role used to create EC2 infrastructure (instances, DNS entries...)

def AWS_ID = "AwsDspDevAutoAccount" // ID of Jenkins credentials that safely stores AWS keys

def AWS_REGION = "us-east-1" // Region to create EC2 infrastructure in

withAWS(region: AWS_REGION, role: AWS_ROLE, credentials: AWS_ID)

  1. Print env vars (in this instance on windows):

echo "ENVIRONMENT VARIABLES FOR THIS BUILD:" echo "set"

Expected behavior: AWS secret access keys should be scrubbed from log (****) like username and passwords pulled out of withCredentials()

Actual behavior: [What actually happened] AWS key, secret and session token are visible in log file:

AWS_ACCESS_KEY_ID=ASIAU11111111GH7B
AWS_DEFAULT_REGION=us-east-1
AWS_REGION=us-east-1
AWS_SECRET_ACCESS_KEY=1111++5bT/WEVfD
AWS_SESSION_TOKEN=11111wEaDLzAu+u2D/gC5pAsiCL8ASAxtPdkR+ouQHwAD4B/3SV0miFuWT1ENRgEmj/PBz3AYz6E1RW3OgeSFo9qVgermFiqSab2O7vMWTei3G7mmo+/m2O9uoMgFHpgVVkCceco+PlolpAcRBKtSWVunL7XDfhhIV9zaC+CiZqxuS2VizsVT0JulTcBZaljHMLX1Mrrv7i7EB5e9e/3Psl34o/vmi0rkm1m49bqn3YP0la6WdoOrBBH6tyuN68dCuMsLxwT8j1Q0ANZktQONURauPUTYopw2g7ch2/jRuO46v46GGf8E9fQOjunaLFpTfavKjIjE+fOvU3BH2GT/1111111111111111111111111==

mattemoore avatar Jan 03 '19 02:01 mattemoore

Hi, this sounds like a good idea, but this is not something this plugin cloud fix. Jenkins should detect the Env Vars and remove them from them log. The plugin just sets normal environment variables. But if you know how I can fix this, I am happy to do it.

hoegertn avatar Jan 03 '19 10:01 hoegertn

@hoegertn the masking of sensitive information is done in the withCredentials() step: https://jenkins.io/doc/pipeline/steps/credentials-binding/:

The secret(s) will be masked (****) in case they are printed to the build log. This prevents you from accidentally disclosing passwords and the like via the log.

The Credentials Binding Plugin does this via its SecretBuildWrapper object: https://github.com/jenkinsci/credentials-binding-plugin/blob/master/src/main/java/org/jenkinsci/plugins/credentialsbinding/impl/SecretBuildWrapper.java

If you implement this then there would no way to have the AWS key, secret and session token in the log file if a pipeline prints any of these env vars in the pipeline log.

mattemoore avatar Jan 03 '19 17:01 mattemoore

Honestly, I do not understand how to use this to create secret environment variables.

hoegertn avatar Jan 06 '19 13:01 hoegertn

To be clear we don't need to create 'secret environment variables' but rather have the AWS secrets masked when ever they are printed to the log file. The environment variables are just an example of how AWS secrets could be printed mistakenly to the log file.

mattemoore avatar Jan 06 '19 23:01 mattemoore

But how should the plugin prevent printing secrets to the console?

hoegertn avatar Jan 06 '19 23:01 hoegertn

That's why i linked the https://jenkins.io/doc/pipeline/steps/credentials-binding/ plugin source above as that plugin masks passwords if they are printed to the build log.

mattemoore avatar Jan 07 '19 15:01 mattemoore

I have 2 issues with this plugin:

  1. unmasked output of secrets
  2. doesnt export AWS_SESSION_TOKEN when the role is set in the credentials

Both are solved by using withCredentials as suggested by @mattemoore

For example, I have a credentials created by doing:

  1. Navigate to Jenkins > Credentials > System > Global credentials
  2. Hit Add Credentials in the left menu
  3. Fill out the form as follows:
    • Kind: AWS Credentials
    • ID: my-example-creds
    • Access Key ID / Secret Access Key: leave blank if using EC2 instance role or fill in normally
    • IAM Role Support:
      • IAM Role To Use: arn:aws:iam::123456789:role/MyExampleRole

Then trying to use this plugin I have something like:

withAws(credentials: 'my-example-creds') {
   sh 'env'
   sh 'aws sts get-caller-identity'
}

Which prints out:

AWS_ACCESS_KEY_ID=ASIA6KZ24U
AWS_SECRET_ACCESS_KEY=hsumKz15FNRaOli4Eki1J

And then the get-caller-identity call fails with the following error because AWS_SESSION_TOKEN was not set.

InvalidClientTokenId The security token included in the request is invalid.

Contrast that with running this:

withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', credentialsId: 'my-example-creds']]) {
   sh 'env'
   sh 'aws sts get-caller-identity'
}

Which outputs:

AWS_SECRET_ACCESS_KEY=****
AWS_ACCESS_KEY_ID=****
AWS_SESSION_TOKEN=****

Note that it is masked and AWS_SESSION_TOKEN is defined.

Then also the get-caller-identity call succeeds:

{
    "Account": "123456789", 
    "UserId": "AROA6KS6TCS:MyExampleUser", 
    "Arn": "arn:aws:sts::123456789:assumed-role/MyExampleRole/MyExampleUser"
}

withAws(credentials: 'my-example-creds') is far more expressive and readable than withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', credentialsId: 'my-example-creds']]) so it'd be really nice if under the hood they did the same thing.

Maybe there is a way that if you get a call to withAws that only provides a credentials param, that is somehow passed off to withCredentials for handling?

This is the plugin that provides the AWS Credentials option when creating credentials: https://github.com/jenkinsci/aws-credentials-plugin

This is the plugin that provides the withCredentials step and does the masking: https://github.com/jenkinsci/credentials-binding-plugin

JoshCoady avatar Dec 12 '19 02:12 JoshCoady

I got stumped on this too, is there a plan to fix this? thanks

rongshen avatar Sep 17 '20 19:09 rongshen

For declarative pipeline, initialize AWS credentials in the environment block. It is pretty concise,

stage("my aws stage") {
    environment {
        NOOP_CREDS_VAR = credentials('my-example-creds')
    }
    steps {
        sh 'env'
        sh 'aws sts get-caller-identity'
    }
}

The environment block syntax requires the actual assignment of creds to a variable, hence NOOP_CREDS_VAR

On aside note. This issue is a glaring security hole and prevents the plugin adoption

apogrebnyak avatar Jan 14 '21 12:01 apogrebnyak