summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2023-03-10 20:38:34 +0100
committerChristian Breunig <christian@breunig.cc>2023-03-10 21:16:44 +0100
commitfe82d86d3e87cb8d92ebc9d0652c08e3dd79a12c (patch)
tree47eb28b4afe3ad104e8542461cde985cec2d125d
parentb4af532dd531c23bc1ad84cca290916be55357bf (diff)
downloadvyos-1x-fe82d86d3e87cb8d92ebc9d0652c08e3dd79a12c.tar.gz
vyos-1x-fe82d86d3e87cb8d92ebc9d0652c08e3dd79a12c.zip
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.
-rw-r--r--data/templates/container/registries.conf.j26
-rw-r--r--interface-definitions/container.xml.in9
-rw-r--r--interface-definitions/include/generic-password.xml.i15
-rw-r--r--interface-definitions/include/generic-username.xml.i15
-rw-r--r--interface-definitions/include/interface/authentication.xml.i28
-rwxr-xr-xsrc/conf_mode/container.py37
6 files changed, 79 insertions, 31 deletions
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 @@
</leafNode>
</children>
</tagNode>
- <leafNode name="registry">
+ <tagNode name="registry">
<properties>
<help>Registry Name</help>
- <multi/>
</properties>
<defaultValue>docker.io quay.io</defaultValue>
- </leafNode>
+ <children>
+ #include <include/interface/authentication.xml.i>
+ #include <include/generic-disable-node.xml.i>
+ </children>
+ </tagNode>
</children>
</node>
</interfaceDefinition>
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 @@
+<!-- include start from generic-password.xml.i -->
+<leafNode name="password">
+ <properties>
+ <help>Password used for authentication</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>Password</description>
+ </valueHelp>
+ <constraint>
+ <regex>[[:ascii:]]{1,128}</regex>
+ </constraint>
+ <constraintErrorMessage>Password is limited to ASCII characters only, with a total length of 128</constraintErrorMessage>
+ </properties>
+</leafNode>
+<!-- include end -->
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 @@
+<!-- include start from generic-username.xml.i -->
+<leafNode name="username">
+ <properties>
+ <help>Username used for authentication</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>Username</description>
+ </valueHelp>
+ <constraint>
+ <regex>[[:ascii:]]{1,128}</regex>
+ </constraint>
+ <constraintErrorMessage>Username is limited to ASCII characters only, with a total length of 128</constraintErrorMessage>
+ </properties>
+</leafNode>
+<!-- include end -->
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 @@
<help>Authentication settings</help>
</properties>
<children>
- <leafNode name="username">
- <properties>
- <help>Username used for authentication</help>
- <valueHelp>
- <format>txt</format>
- <description>Username</description>
- </valueHelp>
- <constraint>
- <regex>[[:ascii:]]{1,128}</regex>
- </constraint>
- <constraintErrorMessage>Username is limited to ASCII characters only, with a total length of 128</constraintErrorMessage>
- </properties>
- </leafNode>
- <leafNode name="password">
- <properties>
- <help>Password used for authentication</help>
- <valueHelp>
- <format>txt</format>
- <description>Password</description>
- </valueHelp>
- <constraint>
- <regex>[[:ascii:]]{1,128}</regex>
- </constraint>
- <constraintErrorMessage>Password is limited to ASCII characters only, with a total length of 128</constraintErrorMessage>
- </properties>
- </leafNode>
+ #include <include/generic-username.xml.i>
+ #include <include/generic-password.xml.i>
</children>
</node>
<!-- include end -->
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)