1

I observe a scenario when I'm writing a Jenkinsfile to first authenticate a session on AWS and then push a dockerfile to designated ECR. The below code block works fine and pushes the image to ECR:

        stage('build and push images') {
            steps {
                sh """
                sh assume_role.sh
                source /tmp/${assume_role_session_name}
                aws ecr get-login --region ${aws_region} --registry-ids ${ROLEARN} --no-include-email
                docker build -t my-docker-image .  
                docker tag my-docker-image:latest ${ROLEARN}.dkr.ecr.${aws_region}.amazonaws.com/${ECR_name}:${ECS_TAG_VERSION}
                docker push ${ROLEARN}.dkr.ecr.${aws_region}.amazonaws.com/${ECR_name}:${ECS_TAG_VERSION}
                docker rmi -f my-docker-image:latest
                """
            }
        }

However, when I divided each step with an individual sh command (like below), docker push failed because the Jenkins agent hasn't been authenticated, which means the authentication token isn't passed to docker push command line.

        stage('build and push images') {
            steps {
                sh "assume_role.sh"
                sh "source /tmp/${assume_role_session_name}"
                sh "aws ecr get-login --region ${aws_region} --registry-ids ${ROLEARN} --no-include-email"
                sh "docker build -t my-docker-image . "
                sh "docker tag my-docker-image:latest ${ROLEARN}.dkr.ecr.${aws_region}.amazonaws.com/${ECR_name}:${ECS_TAG_VERSION}"
                sh "docker push ${ROLEARN}.dkr.ecr.${aws_region}.amazonaws.com/${ECR_name}:${ECS_TAG_VERSION}"
                sh "docker rmi -f my-docker-image:latest"
            }
        }

Thus, I'm suspecting that the each sh starts a new session in Jenkins steps, in between which, authentication tokens cannot be passed through. I don't know whether my guess is correct and how to find evidence to support my guess.

Wendy Zhu
  • 31
  • 3
  • 1
    Every invocation starts a new POSIX shell child process and runs the command in it. Hence, variable set in one process, are invisible in the others. BTW, there does not seem to be _bash_ involved in your question, and I suggest that you replace the _bash_ tag by a _shell_ tag. Also, remove the _groovy_ tag, since this seems to be unrelated too. – user1934428 Feb 03 '21 at 09:11
  • In term of maintenance, it's better to put all commands (aws, docker ...) in a single script (called do_all.sh), then in jenkins, use `steps {sh "do_all.sh"}` – Philippe Feb 03 '21 at 09:31
  • You might get away with something as simple as `sh "source /tmp.... && docker push ..."` – chepner Feb 03 '21 at 16:34
  • Thanks @user1934428, your answer solves what confused me for a while! That's really helpful. Plus, tags are updated. – Wendy Zhu Feb 03 '21 at 20:13

1 Answers1

0

I thought I would share my solution on how I overcame the annoying need to repeatedly assume the role in every sh block. Passing the extracted credentials (dynamically of course) as environment variables solved the issue for me, and there was no need to re-authenticate again in different scripts.

Adding the credentials to the environment variables forces each script to use them.

environment {
    ACCESS = sh(
        returnStdout: true, 
        script: ''' 

            echo "$(aws \
                sts assume-role \
                --role-arn="arn:aws:iam::\${AWS_ACCOUNT_DEV}:role/\${ASSUME_ROLE}" \
                --role-session-name="jenkins" \
                --output json
            )" 


            '''
        ).trim()

}

stages{
    stage('Create env variables') {
        steps {
            script { 
                env.AWS_ACCESS_KEY_ID  = sh(
                    returnStdout: true, 
                    script: '''

                        echo "${ACCESS}" | jq -re '.Credentials.AccessKeyId' 

                    '''
                ).trim()

                env.AWS_SECRET_ACCESS_KEY  = sh(
                    returnStdout: true, 
                    script: '''

                        echo "${ACCESS}" | jq -re '.Credentials.SecretAccessKey'
                        
                    '''
                ).trim()

                env.AWS_SESSION_TOKEN  = sh(
                    returnStdout: true, 
                    script: '''

                        echo "${ACCESS}" | jq -re '.Credentials.SessionToken'
                        
                    '''
                ).trim()
            }
        }
    }
}

To your question, this StackOverflow answer describes what happens to the environment variables set within the sh execution.

Hope this helps ;)

milieere
  • 91
  • 1
  • 3