i am trying to trigger a google cli command in jenkins pipeline.
gcloud auth activate-service-account --key-file=user.json
currently using googlesdk docker image
Here i have my private key stored as credentials in Jenkins server while running command directly from agent i can authenticate to the account. now i wanted to run command inside docker container.
need to know how can i access private key stored in Jenkins from Docker container ?
i tried to access it directly and got following error message
ERROR: gcloud crashed (ValueError): No key could be detected.
some Assistance will be helpful.
i use scripted pipeline.
Related
I'm trying to run a TFS agent as a service in a Windows Server Docker Container. I am able to get the agent running if I use the run.cmd but when attempting to configure the agent to run as a service I'm getting the error Below.
I have ensured the account is a local administrator and have tried the local system account and seem to be getting the same error. Thanks
Exit code -1073741502 returned from process: file name 'C:\TFSAgent\bin\AgentService.exe', arguments 'init'.
Command I'm using:
.\config.cmd --unattended --url https://tfsurl --auth Negotiate --username username --password password --pool Sandbox --agent dockeragent --runasservice --windowslogonaccount
username --windowslogonpassword password --replace
Run TFS Agent as Service in Docker Container
According to the document Define container jobs, which need to make sure:
The agent must have permission to access the Docker daemon
To run a self-hosted agent in Docker, you could refer following document:
Run a self-hosted agent in Docker
Running Azure DevOps private agents as docker containers
I've setup Jenkins on a Google Cloud compute engine vm. Docker is installed, and I'm successfully using a scripted pipeline to pull and run public docker images. I can't seem to pull from Google Container registry though, and I can't find any examples of how to do this in a scripted pipeline. Here's my Jenkinsfile:
node {
checkout scm
docker.image('mysql:5.7').withRun('--env MYSQL_DATABASE=my_db --env MYSQL_ROOT_PASSWORD=password -p 3306:3306') { c ->
docker.image('mysql:5.7').inside("--link ${c.id}:db") {
/* Wait until mysql service is up */
sh 'while ! mysqladmin ping -hdb --silent; do sleep 1; done'
}
/* Fails here */
docker.image('gcr.io/my-project/my-image').withRun("--link ${c.id}:db --env MYSQL_HOST=localhost --env MYSQL_USER=root --env MYSQL_PWD=password --env MYSQL_DB=my_db --network=host")
}
}
It seems like since I'm on a compute engine vm, there shouldn't need to be any credential configuration for Jenkins (clearly I'm wrong). I've run gcloud auth configure-docker on the vm, and I can easily ssh in and pull the image I want from gcr.io with a simple docker pull. When jenkins tries to pull though, I get Error response from daemon: unauthorized: You don't have the needed permissions to perform this operation, and you may have invalid credentials. To authenticate your request, follow the steps in: https://cloud.google.com/container-registry/docs/advanced-authentication.
Any ideas?
Edit:
I've discovered wrapping my pull step with docker.withRegistry() works, but this requires me to add my gcloud credentials via the Jenkins interface. It seems strange that I need to do this since Jenkins is already running on a compute engine vm that has the correct auth and docker correctly configured to be able to pull from gcr.io. Is there some special way Jenkins (or the docker pipeline plugin) is running docker that it somehow doesn't have the same authentication that docker has when run manually on the vm?
Cracked this, and it was a bit silly. While I did indeed setup auth correctly for my user on the vm, I did not do this for the jenkins user on the vm. After ssh-ing into the vm, I needed to do:
sudo su jenkins
gcloud auth configure-docker
This adds the gcloud config for docker to jenkins' home directory. Then you have no need for withRegistry or any additional jenkins credential configuration. Nice and clean if you are doing this on a vm.
It looks like that you’re running into some auth issues with Jenkins & Docker on a GCE VM.
This document may help [1], and also, did you have the chance of looking into a helper [2]?
[1] https://googleapis.dev/python/google-api-core/latest/auth.html#using-google-compute-engine
[2] https://cloud.google.com/container-registry/docs/advanced-authentication#helpers
I have the following script ( I've change the AZURE_PIPELINES_PUBLISHER ):
AZURE_PIPELINES_PUBLISHER=azure-pipelines-publisher#$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
--member serviceAccount:$AZURE_PIPELINES_PUBLISHER \
--role roles/storage.admin
I write this script on 'Arguments' field of the Docker push task, in Azure DevOps, when i run the build, this task shows the following error:
unknown flag: --member
I get the script from the Google Cloud documentation.
What's wrong in the script?
From the tutorial, gcloud command should run in the Cloud Shell. It's not 'Arguments' of the Docker push task. It's supposed creating a Google Cloud service account in your production project and assign the role before you configure Azure Pipelines to build and publish a container image.
I've discovered a flow that works through GCP console but not through the gcloud CLI.
Minimal Repro
The following bash snippet creates a fresh GCP project and attempts to push an image to gcr.io, but fails with "access denied" even though the user is project owner:
gcloud auth login
PROJECT_ID="example-project-20181120"
gcloud projects create "$PROJECT_ID" --set-as-default
gcloud services enable containerregistry.googleapis.com
gcloud auth configure-docker --quiet
mkdir ~/docker-source && cd ~/docker-source
git clone https://github.com/mtlynch/docker-flask-upload-demo.git .
LOCAL_IMAGE_NAME="flask-demo-app"
GCR_IMAGE_PATH="gcr.io/${PROJECT_ID}/flask-demo-app"
docker build --tag "$LOCAL_IMAGE_NAME" .
docker tag "$LOCAL_IMAGE_NAME" "$GCR_IMAGE_PATH"
docker push "$GCR_IMAGE_PATH"
Result
The push refers to repository [gcr.io/example-project-20181120/flask-demo-app]
02205dbcdc63: Preparing
06ade19a43a0: Preparing
38d9ac54a7b9: Preparing
f83363c693c0: Preparing
b0d071df1063: Preparing
90d1009ce6fe: Waiting
denied: Token exchange failed for project 'example-project-20181120'. Access denied.
The system is Ubuntu 16.04 with the latest version of gcloud 225.0.0, as of this writing. The account I auth'ed with has role roles/owner.
Inconsistency with GCP Console
I notice that if I follow the same flow through GCP Console, I can docker push successfully:
Create a new GCP project via GCP Console
Create a service account with roles/owner via GCP Console
Download JSON key for service account
Enable container registry API via GCP Console
gcloud auth activate-service-account --key-file key.json
gcloud config set project $PROJECT_ID
gcloud auth configure-docker --quiet
docker tag "$LOCAL_IMAGE_NAME" "$GCR_IMAGE_PATH" && docker push "$GCR_IMAGE_PATH"
Result: Works as expected. Successfully pushes docker image to gcr.io.
Other attempts
I also tried using gcloud auth login as my #gmail.com account, then using that account to create a service account with gcloud, but that gets the same denied error:
SERVICE_ACCOUNT_NAME=test-service-account
gcloud iam service-accounts create "$SERVICE_ACCOUNT_NAME"
KEY_FILE="${HOME}/key.json"
gcloud iam service-accounts keys create "$KEY_FILE" \
--iam-account "${SERVICE_ACCOUNT_NAME}#${PROJECT_ID}.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
--member "serviceAccount:${SERVICE_ACCOUNT_NAME}#${PROJECT_ID}.iam.gserviceaccount.com" \
--role roles/owner
gcloud auth activate-service-account --key-file="${HOME}/key.json"
docker push "$GCR_IMAGE_PATH"
Result: denied: Token exchange failed for project 'example-project-20181120'. Access denied.
I tried to reproduce the same error using bash snippet you provided, however it successfully built the ‘flask-demo-app’ container registry image for me. I used below steps to reproduce the issue:
Step 1: Use account which have ‘role: roles/owner’ and ‘role: roles/editor’
Step 2: Created bash script using your given snippet
Step 3: Added ‘gcloud auth activate-service-account --key-file skey.json’ in script to authenticate the account
Step 4: Run the bash script
Result : It created the ‘flask-demo-app’ container registry image
This leads me to believe that there might be an issue with your environment which is causing this error for you. To troubleshoot this you could try running your code on a different machine, a different network or even on the Cloud Shell.
In my case project IAM permission was the issue. Make sure proper permission given and also cloud resource/container registry API enabled.
GCP Access Control
I have a GitLab project gitlab.com/my-group/my-project which has a CI pipeline that builds an image and pushes it to the project's GitLab registry registry.gitlab.com/my-group/my-project:tag. I want to deploy this image to Google Compute Engine, where I have a VM running docker.
Easy enough to do it manually by ssh'ing into the VM, then docker login registry.gitlab.com and docker run ... registry.gitlab.com/my-group/my-project:tag. Except the docker login command is interactive, which is a no-go for CI. It can accept a username and password on the command line, but that hardly feels like the right thing to do, even if my login info is in a secret variable (storing my GitLab login credentials in a GitLab secret variable?...)
This is the intended workflow on the Deploy stage of the pipeline:
Either install the gcloud tool or use an image with it preinstalled
gcloud compute ssh my-gce-vm-name --quiet --command \
"docker login registry.gitlab.com && docker run registry.gitlab.com/my-group/my-project:tag"
Since the gcloud command would be running within the GitLab CI Runner, it could have access to secret variables, but is that really the best way to log in to the GitLab Registry over ssh from GitLab?
I'll answer my own question in case anyone else stumbles upon it. GitLab creates ephemeral access tokens for each build of the pipeline that give the user gitlab-ci-token access to the GitLab Registry. The solution was to log in as the gitlab-ci-token user in the build.
.gitlab-ci.yml (excerpt):
deploy:
stage: deploy
before_script:
- gcloud compute ssh my-instance-name --command "docker login registry.gitlab.com/my-group/my-project -u gitlab-ci-token -p $CI_BUILD_TOKEN"
The docker login command creates a local configuration file in which your credentials are stored at $HOME/.docker/config.json that looks like this (also see the documentation on this):
{
"auths": {
"<registry-url>": {
"auth": "<credentials>"
}
}
}
As long as the config.json file is present on your host and your credentials (in this case simply being stored as base64("<username>:<password>")) do not change, there is no need to run docker login on every build or to store your credentials as variables for your CI job.
My suggestion would be to simply ensure that the config.json file is present on your target machine (either by running docker login once manually or by deploying the file using whatever configuration management tool you like). This saves you from handling the login and managing credentials within your build pipeline.
Regarding the SSH login per se; this should work just fine. If you really want to eliminate the SSH login, you could setup the Docker engine on your target machine to listen on an external socket, configure authentication and encryption using TLS client certificates as described in the official documentation and directly talk to the remote server's Docker API from within the build job:
variables:
DOCKER_HOST: "tcp://<target-server>:2376"
DOCKER_TLS_VERIFY: "1"
script:
- docker run registry.gitlab.com/my-group/my-project:tag
We had the same "problem" on other hosting providers. Our solution is to use some kind of custom script which runs on the target machine and can be called via a Rest-Api Endpoint (secured by Basic-Auth or what ever).
So you could just trigger the remote host to do the docker login and upgrade your service without granting SSH Access via gitlab-ci.