Add support for SSH deploy key cloning

This commit is contained in:
Joshua Boniface 2021-10-31 02:11:57 -04:00
parent 54d5837515
commit d366f08a3f
4 changed files with 34 additions and 5 deletions

View File

@ -117,3 +117,13 @@ You can extrapolate from here how to leverage Basic Builder to perform other tas
**NOTE:** The commands specified in `.bbuilder-tasks.yaml` are always run relative to the root of the repository on the relevant `ref`, either a branch for `push` events, or a tag for `create` or `release` events. **NOTE:** The commands specified in `.bbuilder-tasks.yaml` are always run relative to the root of the repository on the relevant `ref`, either a branch for `push` events, or a tag for `create` or `release` events.
**NOTE:** The commands specified in `.bbuilder-tasks.yaml` are run with the privileges of the `bbuilder worker` process. Normally, this should not be `root`, but if it does need to be, **be very careful and remember that Basic Builder is implicitly trusting the content of this configuration in all repositories it is configured for**. **NOTE:** The commands specified in `.bbuilder-tasks.yaml` are run with the privileges of the `bbuilder worker` process. Normally, this should not be `root`, but if it does need to be, **be very careful and remember that Basic Builder is implicitly trusting the content of this configuration in all repositories it is configured for**.
## Cloning Repositories
The Basic Builder worker will, by default, attempt to clone repositories via HTTP(S). This may cause problems if the repository is private however. To work around this, Basic Builder supports de;poy keys, i.e. dedicated SSH keypairs that the system can use to clone a repository over SSH instead of HTTP(S).
To activate this functionality, you can use the `-k`/`--ssh-key` option to the `bbuilder worker` command or the `BB_SSH_KEY` environment variable to set a path to an SSH private key which will be used.
This key should be kept secure and only readable by the Basic Builder user.
On the repository side, the key should be added as a deploy key (e.g. in Gitea, under the repository `Settings` -> `Deploy Keys`) for the specific repositories that require it.

View File

@ -32,10 +32,21 @@ def print_version(ctx, param, value):
default=1, show_default=True, default=1, show_default=True,
help='The concurrency of the Celery worker. Envvar: BB_CONCURRENCY' help='The concurrency of the Celery worker. Envvar: BB_CONCURRENCY'
) )
def cli_worker(concurrency): @click.option(
'-k', '--ssh-key', 'ssh_key', envvar='BB_SSH_KEY',
default=None,
help='An SSH private key (deploy key) to clone repositories. Envvar: BB_SSH_KEY'
)
def cli_worker(concurrency, ssh_key):
""" """
Run a Basic Builder worker Run a Basic Builder worker
Note: If '-s'/'--ssh-key'/'BB_SSH_KEY' is not specified, Basic Builder will attempt to clone repositories over HTTP(S) instead. They must be publicly accessible without anthentication in this case.
""" """
if ssh_key == '':
ssh_key = None
config['ssh_key'] = ssh_key
celery = Celery('bbuilder', broker=config['broker']) celery = Celery('bbuilder', broker=config['broker'])
@celery.task(bind=True) @celery.task(bind=True)

View File

@ -32,7 +32,7 @@ def create_workdir(config, task_id):
rmtree(workdir) rmtree(workdir)
def handle_event_gitea(request): def handle_event_gitea(request, config):
event = request[0].get('X-Gitea-Event', None) event = request[0].get('X-Gitea-Event', None)
if event is None: if event is None:
meta = f'FATAL: No X-Gitea-Event header in request' meta = f'FATAL: No X-Gitea-Event header in request'
@ -47,6 +47,9 @@ def handle_event_gitea(request):
if repository is None: if repository is None:
meta = f'FATAL: No repository information in request JSON body' meta = f'FATAL: No repository information in request JSON body'
raise TaskFailure(meta) raise TaskFailure(meta)
if config['ssh_key'] is not None:
clone_url = repository.get('ssh_url')
else:
clone_url = repository.get('clone_url') clone_url = repository.get('clone_url')
# Get the event action (only relevant to Release events) # Get the event action (only relevant to Release events)
@ -92,8 +95,12 @@ def handle_event_gitea(request):
return event, event_action, clone_url, ref return event, event_action, clone_url, ref
def clone_repository(clone_url): def clone_repository(clone_url, config):
print(f"Cloning repository...") print(f"Cloning repository...")
if config['ssh_key'] is not None:
ssh_key_file = config['ssh_key']
os.environ['GIT_SSH_COMMAND='] = f'ssh -i {ssh_key_file} -o IdentitiesOnly=yes'
os.system(f'git clone {clone_url} repo') os.system(f'git clone {clone_url} repo')
@ -138,7 +145,7 @@ def do_task(self, config, hooktype, request):
meta = f'FATAL: Hook type "{hooktype}" is not valid.' meta = f'FATAL: Hook type "{hooktype}" is not valid.'
raise TaskFailure(meta) raise TaskFailure(meta)
event, event_action, clone_url, ref = hooktype_dict.get(hooktype)(request) event, event_action, clone_url, ref = hooktype_dict.get(hooktype)(request, config)
print(f"Event type: {event}") print(f"Event type: {event}")
print(f"Clone URL: {clone_url}") print(f"Clone URL: {clone_url}")

View File

@ -6,3 +6,4 @@ BB_LISTEN_ADDR="0.0.0.0"
BB_LISTEN_PORT="7999" BB_LISTEN_PORT="7999"
BB_AUTH_KEY="I'mALittleTeapot" BB_AUTH_KEY="I'mALittleTeapot"
BB_CONCURRENCY=1 BB_CONCURRENCY=1
BB_SSH_KEY="/path/to/deploy/id_ed25519"