From fe82d86d3e87cb8d92ebc9d0652c08e3dd79a12c Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Fri, 10 Mar 2023 20:38:34 +0100 Subject: container: T4959: add registry authentication option Container registry CLI node changed from leafNode to tagNode with the same defaults. In addition we can now configure an authentication option per registry. --- data/templates/container/registries.conf.j2 | 6 +++- interface-definitions/container.xml.in | 9 ++++-- .../include/generic-password.xml.i | 15 +++++++++ .../include/generic-username.xml.i | 15 +++++++++ .../include/interface/authentication.xml.i | 28 ++-------------- src/conf_mode/container.py | 37 +++++++++++++++++++++- 6 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 interface-definitions/include/generic-password.xml.i create mode 100644 interface-definitions/include/generic-username.xml.i diff --git a/data/templates/container/registries.conf.j2 b/data/templates/container/registries.conf.j2 index 2e86466a1..eb7ff8775 100644 --- a/data/templates/container/registries.conf.j2 +++ b/data/templates/container/registries.conf.j2 @@ -23,5 +23,9 @@ # unqualified-search-registries = ["example.com"] {% if registry is vyos_defined %} -unqualified-search-registries = {{ registry }} +{% set registry_list = [] %} +{% for r, r_options in registry.items() if r_options.disable is not vyos_defined %} +{% set _ = registry_list.append(r) %} +{% endfor %} +unqualified-search-registries = {{ registry_list }} {% endif %} diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in index a5940ae17..6947ed500 100644 --- a/interface-definitions/container.xml.in +++ b/interface-definitions/container.xml.in @@ -368,13 +368,16 @@ - + Registry Name - docker.io quay.io - + + #include + #include + + diff --git a/interface-definitions/include/generic-password.xml.i b/interface-definitions/include/generic-password.xml.i new file mode 100644 index 000000000..76d5f12d8 --- /dev/null +++ b/interface-definitions/include/generic-password.xml.i @@ -0,0 +1,15 @@ + + + + Password used for authentication + + txt + Password + + + [[:ascii:]]{1,128} + + Password is limited to ASCII characters only, with a total length of 128 + + + diff --git a/interface-definitions/include/generic-username.xml.i b/interface-definitions/include/generic-username.xml.i new file mode 100644 index 000000000..678f30ddf --- /dev/null +++ b/interface-definitions/include/generic-username.xml.i @@ -0,0 +1,15 @@ + + + + Username used for authentication + + txt + Username + + + [[:ascii:]]{1,128} + + Username is limited to ASCII characters only, with a total length of 128 + + + diff --git a/interface-definitions/include/interface/authentication.xml.i b/interface-definitions/include/interface/authentication.xml.i index ac06faef5..0bd792209 100644 --- a/interface-definitions/include/interface/authentication.xml.i +++ b/interface-definitions/include/interface/authentication.xml.i @@ -4,32 +4,8 @@ Authentication settings - - - Username used for authentication - - txt - Username - - - [[:ascii:]]{1,128} - - Username is limited to ASCII characters only, with a total length of 128 - - - - - Password used for authentication - - txt - Password - - - [[:ascii:]]{1,128} - - Password is limited to ASCII characters only, with a total length of 128 - - + #include + #include diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py index 10e9e9213..68070ea5b 100755 --- a/src/conf_mode/container.py +++ b/src/conf_mode/container.py @@ -18,7 +18,6 @@ import os from ipaddress import ip_address from ipaddress import ip_network -from time import sleep from json import dumps as json_write from vyos.base import Warning @@ -28,6 +27,7 @@ from vyos.configdict import node_changed from vyos.util import call from vyos.util import cmd from vyos.util import run +from vyos.util import rc_cmd from vyos.util import write_file from vyos.template import inc_ip from vyos.template import is_ipv4 @@ -68,6 +68,9 @@ def get_config(config=None): # container base default values can not be merged here - remove and add them later if 'name' in default_values: del default_values['name'] + # registry will be handled below + if 'registry' in default_values: + del default_values['registry'] container = dict_merge(default_values, container) # Merge per-container default values @@ -95,6 +98,15 @@ def get_config(config=None): container['name'][name]['volume'][volume] = dict_merge( default_values_volume, container['name'][name]['volume'][volume]) + # registry is a tagNode with default values - merge the list from + # default_values['registry'] into the tagNode variables + if 'registry' not in container: + container.update({'registry' : {}}) + default_values = defaults(base) + for registry in default_values['registry'].split(): + tmp = {registry : {}} + container['registry'] = dict_merge(tmp, container['registry']) + # Delete container network, delete containers tmp = node_changed(conf, base + ['network']) if tmp: container.update({'network_remove' : tmp}) @@ -226,6 +238,11 @@ def verify(container): if 'network' in container_config and network in container_config['network']: raise ConfigError(f'Can not remove network "{network}", used by container "{container}"!') + if 'registry' in container and 'authentication' in container['registry']: + for registry, registry_config in container['registry']['authentication'].items(): + if not {'username', 'password'} <= set(registry_config): + raise ConfigError('If registry username or or password is defined, so must be the other!') + return None def generate_run_arguments(name, container_config): @@ -355,6 +372,24 @@ def generate(container): write_file(f'/etc/cni/net.d/{network}.conflist', json_write(tmp, indent=2)) + if 'registry' in container: + cmd = f'podman logout --all' + rc, out = rc_cmd(cmd) + if rc != 0: + raise ConfigError(out) + + for registry, registry_config in container['registry'].items(): + if 'disable' in registry_config: + continue + if 'authentication' in registry_config: + if {'username', 'password'} <= set(registry_config['authentication']): + username = registry_config['authentication']['username'] + password = registry_config['authentication']['password'] + cmd = f'podman login --username {username} --password {password} {registry}' + rc, out = rc_cmd(cmd) + if rc != 0: + raise ConfigError(out) + render(config_containers_registry, 'container/registries.conf.j2', container) render(config_containers_storage, 'container/storage.conf.j2', container) -- cgit v1.2.3