mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-12 06:56:24 +00:00
feat(docker): Support for Bearer token to access the Docker registry (#10400)
This commit is contained in:
parent
5c21d44055
commit
d4a22c7f3c
3 changed files with 101 additions and 1 deletions
|
@ -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
|
#### ChartMuseum
|
||||||
|
|
||||||
Maybe you're running your own ChartMuseum server to host your private Helm Charts.
|
Maybe you're running your own ChartMuseum server to host your private Helm Charts.
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import * as httpMock from '../../../test/http-mock';
|
||||||
import { getName, mocked } from '../../../test/util';
|
import { getName, mocked } from '../../../test/util';
|
||||||
import * as _hostRules from '../../util/host-rules';
|
import * as _hostRules from '../../util/host-rules';
|
||||||
import * as dockerCommon from './common';
|
import * as dockerCommon from './common';
|
||||||
|
@ -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",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -81,12 +81,20 @@ export async function getAuthHeaders(
|
||||||
'base64'
|
'base64'
|
||||||
);
|
);
|
||||||
opts.headers = { authorization: `Basic ${auth}` };
|
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.username;
|
||||||
delete opts.password;
|
delete opts.password;
|
||||||
|
delete opts.token;
|
||||||
|
|
||||||
if (authenticateHeader.scheme.toUpperCase() === 'BASIC') {
|
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);
|
await http.get(apiCheckUrl, opts);
|
||||||
return opts.headers;
|
return opts.headers;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue