Skip to content

Commit

Permalink
feat(docker): Support for Bearer token to access the Docker registry (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsbasjes authored Jun 16, 2021
1 parent 5c21d44 commit d4a22c7
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 1 deletion.
47 changes: 47 additions & 0 deletions docs/usage/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,53 @@ module.exports = {
};
```

#### Google Container Registry

Assume you are running GitLab CI in the Google Cloud, and you are storing your Docker images in the Google Container Registry (GCR).

Access to the GCR uses Bearer token based authentication.
This token can be obtained by running `gcloud auth print-access-token`, which requires the Google Cloud SDK to be installed.

The token expires after 60 minutes so you cannot store it in a variable for subsequent builds (like you can with `RENOVATE_TOKEN`).

When running Renovate in this context the Google access token must be retrieved and injected into the `hostRules` configuration just before Renovate is started.

_This documentation gives **a few hints** on **a possible way** to achieve this end result._

The basic approach is that you create a custom image and then run Renovate as one of the stages of your project.
To make this run independent of any user you should use a [`Project Access Token`](https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html) (with Scopes: `api`, `read_api` and `write_repository`) for the project and use this as the `RENOVATE_TOKEN` variable for Gitlab CI.
See also the [renovate-runner repository on GitLab](https://gitlab.com/renovate-bot/renovate-runner) where `.gitlab-ci.yml` configuration examples can be found.

To get access to the token a custom Renovate Docker image is needed that includes the Google Cloud SDK.
The Dockerfile to create such an image can look like this:

```Dockerfile
FROM renovate/renovate:25.40.1
# Include the "Docker tip" which you can find here https://cloud.google.com/sdk/docs/install
# under "Installation" for "Debian/Ubuntu"
RUN ...
```

For Renovate to access the Google Container Registry (GCR) it needs the current Google Access Token.
The configuration fragment to do that looks something like this:

```js
hostRules: [
{
matchHost: 'eu.gcr.io',
token: 'MyReallySecretTokenThatExpiresAfter60Minutes',
},
];
```

One way to provide the short-lived Google Access Token to Renovate is by generating these settings into a `config.js` file from within the `.gitlab-ci.yml` right before starting Renovate:

```yaml
script:
- 'echo "module.exports = { hostRules: [ { matchHost: ''eu.gcr.io'', token: ''"$(gcloud auth print-access-token)"'' } ] };" > config.js'
- renovate $RENOVATE_EXTRA_FLAGS
```
#### ChartMuseum
Maybe you're running your own ChartMuseum server to host your private Helm Charts.
Expand Down
45 changes: 45 additions & 0 deletions lib/datasource/docker/common.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as httpMock from '../../../test/http-mock';
import { getName, mocked } from '../../../test/util';
import * as _hostRules from '../../util/host-rules';
import * as dockerCommon from './common';
Expand Down Expand Up @@ -70,4 +71,48 @@ describe(getName(), () => {
`);
});
});
describe('getAuthHeaders', () => {
beforeEach(() => {
httpMock
.scope('https://my.local.registry')
.get('/v2/')
.reply(401, '', { 'www-authenticate': 'Authenticate you must' });
hostRules.hosts.mockReturnValue([]);
});

it('returns "authType token" if both provided', async () => {
hostRules.find.mockReturnValue({
authType: 'some-authType',
token: 'some-token',
});

const headers = await dockerCommon.getAuthHeaders(
'https://my.local.registry',
'https://my.local.registry/prefix'
);

expect(headers).toMatchInlineSnapshot(`
Object {
"authorization": "some-authType some-token",
}
`);
});

it('returns "Bearer token" if only token provided', async () => {
hostRules.find.mockReturnValue({
token: 'some-token',
});

const headers = await dockerCommon.getAuthHeaders(
'https://my.local.registry',
'https://my.local.registry/prefix'
);

expect(headers).toMatchInlineSnapshot(`
Object {
"authorization": "Bearer some-token",
}
`);
});
});
});
10 changes: 9 additions & 1 deletion lib/datasource/docker/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,20 @@ export async function getAuthHeaders(
'base64'
);
opts.headers = { authorization: `Basic ${auth}` };
} else if (opts.token) {
const authType = opts.authType ?? 'Bearer';
logger.trace(
`Using ${authType} token for Docker registry ${registryHost}`
);
opts.headers = { authorization: `${authType} ${opts.token}` };
return opts.headers;
}
delete opts.username;
delete opts.password;
delete opts.token;

if (authenticateHeader.scheme.toUpperCase() === 'BASIC') {
logger.debug(`Using Basic auth for docker registry ${dockerRepository}`);
logger.trace(`Using Basic auth for docker registry ${registryHost}`);
await http.get(apiCheckUrl, opts);
return opts.headers;
}
Expand Down

0 comments on commit d4a22c7

Please sign in to comment.