Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F118310015
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/debian/vyos-1x.postinst b/debian/vyos-1x.postinst
index 141a9e8f9..dc8ada267 100644
--- a/debian/vyos-1x.postinst
+++ b/debian/vyos-1x.postinst
@@ -1,261 +1,264 @@
#!/bin/bash
# Turn off Debian default for %sudo
sed -i -e '/^%sudo/d' /etc/sudoers || true
# Add minion user for salt-minion
if ! grep -q '^minion' /etc/passwd; then
adduser --quiet --firstuid 100 --system --disabled-login --ingroup vyattacfg \
--gecos "salt minion user" --shell /bin/vbash minion
adduser --quiet minion frrvty
adduser --quiet minion sudo
adduser --quiet minion adm
adduser --quiet minion dip
adduser --quiet minion disk
adduser --quiet minion users
adduser --quiet minion frr
fi
# OpenVPN should get its own user
if ! grep -q '^openvpn' /etc/passwd; then
adduser --quiet --firstuid 100 --system --group --shell /usr/sbin/nologin openvpn
fi
# We need to have a group for RADIUS service users to use it inside PAM rules
if ! grep -q '^radius' /etc/group; then
addgroup --firstgid 1000 --quiet radius
fi
# Remove TACACS user added by base package - we use our own UID range and group
# assignments - see below
if grep -q '^tacacs' /etc/passwd; then
if [ $(id -u tacacs0) -ge 1000 ]; then
level=0
vyos_group=vyattaop
while [ $level -lt 16 ]; do
userdel tacacs${level} || true
rm -rf /home/tacacs${level} || true
level=$(( level+1 ))
done 2>&1
fi
fi
# Remove TACACS+ PAM default profile
if [[ -e /usr/share/pam-configs/tacplus ]]; then
rm /usr/share/pam-configs/tacplus
fi
# Add TACACS system users required for TACACS based system authentication
if ! grep -q '^tacacs' /etc/passwd; then
# Add the tacacs group and all 16 possible tacacs privilege-level users to
# the password file, home directories, etc. The accounts are not enabled
# for local login, since they are only used to provide uid/gid/homedir for
# the mapped TACACS+ logins (and lookups against them). The tacacs15 user
# is also added to the sudo group, and vyattacfg group rather than vyattaop
# (used for tacacs0-14).
level=0
vyos_group=vyattaop
while [ $level -lt 16 ]; do
adduser --quiet --system --firstuid 900 --disabled-login --ingroup tacacs \
--no-create-home --gecos "TACACS+ mapped user at privilege level ${level}" \
--shell /bin/vbash tacacs${level}
adduser --quiet tacacs${level} frrvty
adduser --quiet tacacs${level} adm
adduser --quiet tacacs${level} dip
adduser --quiet tacacs${level} users
if [ $level -lt 15 ]; then
adduser --quiet tacacs${level} vyattaop
adduser --quiet tacacs${level} operator
else
adduser --quiet tacacs${level} vyattacfg
adduser --quiet tacacs${level} sudo
adduser --quiet tacacs${level} disk
adduser --quiet tacacs${level} frr
adduser --quiet tacacs${level} _kea
fi
level=$(( level+1 ))
done 2>&1 | grep -v "User tacacs${level} already exists"
fi
# Add RADIUS operator user for RADIUS authenticated users to map to
if ! grep -q '^radius_user' /etc/passwd; then
adduser --quiet --firstuid 1000 --disabled-login --ingroup radius \
--no-create-home --gecos "RADIUS mapped user at privilege level operator" \
--shell /sbin/radius_shell radius_user
adduser --quiet radius_user frrvty
adduser --quiet radius_user vyattaop
adduser --quiet radius_user operator
adduser --quiet radius_user adm
adduser --quiet radius_user dip
adduser --quiet radius_user users
fi
# Add RADIUS admin user for RADIUS authenticated users to map to
if ! grep -q '^radius_priv_user' /etc/passwd; then
adduser --quiet --firstuid 1000 --disabled-login --ingroup radius \
--no-create-home --gecos "RADIUS mapped user at privilege level admin" \
--shell /sbin/radius_shell radius_priv_user
adduser --quiet radius_priv_user frrvty
adduser --quiet radius_priv_user vyattacfg
adduser --quiet radius_priv_user sudo
adduser --quiet radius_priv_user adm
adduser --quiet radius_priv_user dip
adduser --quiet radius_priv_user disk
adduser --quiet radius_priv_user users
adduser --quiet radius_priv_user frr
adduser --quiet radius_priv_user _kea
fi
# add hostsd group for vyos-hostsd
if ! grep -q '^hostsd' /etc/group; then
addgroup --quiet --system hostsd
fi
# Add _kea user for kea-dhcp{4,6}-server to vyattacfg
# The user should exist via kea-common installed as transitive dependency
if grep -q '^_kea' /etc/passwd; then
adduser --quiet _kea vyattacfg
fi
# ensure the proxy user has a proper shell
chsh -s /bin/sh proxy
# Set file capabilities
setcap cap_net_admin=pe /sbin/ethtool
setcap cap_net_admin=pe /sbin/tc
setcap cap_net_admin=pe /bin/ip
setcap cap_net_admin=pe /sbin/xtables-legacy-multi
setcap cap_net_admin=pe /sbin/xtables-nft-multi
setcap cap_net_admin=pe /usr/sbin/conntrack
setcap cap_net_admin=pe /usr/sbin/arp
setcap cap_net_raw=pe /usr/bin/tcpdump
setcap cap_net_admin,cap_sys_admin=pe /sbin/sysctl
setcap cap_sys_module=pe /bin/kmod
setcap cap_sys_time=pe /bin/date
# create needed directories
mkdir -p /var/log/user
mkdir -p /var/core
mkdir -p /opt/vyatta/etc/config/auth
mkdir -p /opt/vyatta/etc/config/scripts
mkdir -p /opt/vyatta/etc/config/user-data
mkdir -p /opt/vyatta/etc/config/support
chown -R root:vyattacfg /opt/vyatta/etc/config
chmod -R 775 /opt/vyatta/etc/config
mkdir -p /opt/vyatta/etc/logrotate
mkdir -p /opt/vyatta/etc/netdevice.d
touch /etc/environment
if [ ! -f /etc/bash_completion ]; then
echo "source /etc/bash_completion.d/10vyatta-op" > /etc/bash_completion
echo "source /etc/bash_completion.d/20vyatta-cfg" >> /etc/bash_completion
fi
sed -i 's/^set /builtin set /' /etc/bash_completion
# Fix up PAM configuration for login so that invalid users are prompted
# for password
sed -i 's/requisite[ \t][ \t]*pam_securetty.so/required pam_securetty.so/' $rootfsdir/etc/pam.d/login
# Change default shell for new accounts
sed -i -e ':^DSHELL:s:/bin/bash:/bin/vbash:' /etc/adduser.conf
# Do not allow users to change full name field (controlled by vyos-1x)
sed -i -e 's/^CHFN_RESTRICT/#&/' /etc/login.defs
# Only allow root to use passwd command
if ! grep -q 'pam_succeed_if.so' /etc/pam.d/passwd ; then
sed -i -e '/^@include/i \
password requisite pam_succeed_if.so user = root
' /etc/pam.d/passwd
fi
# remove unnecessary ddclient script in /etc/ppp/ip-up.d/
# this logs unnecessary messages trying to start ddclient
rm -f /etc/ppp/ip-up.d/ddclient
# create /opt/vyatta/etc/config/scripts/vyos-preconfig-bootup.script
PRECONFIG_SCRIPT=/opt/vyatta/etc/config/scripts/vyos-preconfig-bootup.script
if [ ! -x $PRECONFIG_SCRIPT ]; then
mkdir -p $(dirname $PRECONFIG_SCRIPT)
touch $PRECONFIG_SCRIPT
chmod 755 $PRECONFIG_SCRIPT
cat <<EOF >>$PRECONFIG_SCRIPT
#!/bin/sh
# This script is executed at boot time before VyOS configuration is applied.
# Any modifications required to work around unfixed bugs or use
# services not available through the VyOS CLI system can be placed here.
EOF
fi
# create /opt/vyatta/etc/config/scripts/vyos-postconfig-bootup.script
POSTCONFIG_SCRIPT=/opt/vyatta/etc/config/scripts/vyos-postconfig-bootup.script
if [ ! -x $POSTCONFIG_SCRIPT ]; then
mkdir -p $(dirname $POSTCONFIG_SCRIPT)
touch $POSTCONFIG_SCRIPT
chmod 755 $POSTCONFIG_SCRIPT
cat <<EOF >>$POSTCONFIG_SCRIPT
#!/bin/sh
# This script is executed at boot time after VyOS configuration is fully applied.
# Any modifications required to work around unfixed bugs
# or use services not available through the VyOS CLI system can be placed here.
EOF
fi
# symlink destination is deleted during ISO assembly - this generates some noise
# when the system boots: systemd-sysv-generator[1881]: stat() failed on
# /etc/init.d/README, ignoring: No such file or directory. Thus we simply drop
# the file.
if [ -L /etc/init.d/README ]; then
rm -f /etc/init.d/README
fi
# Remove unwanted daemon files from /etc
# conntackd
# pmacct
# fastnetmon
# ntp
DELETE="/etc/logrotate.d/conntrackd.distrib /etc/init.d/conntrackd /etc/default/conntrackd
/etc/default/pmacctd /etc/pmacct
/etc/networks_list /etc/networks_whitelist /etc/fastnetmon.conf
/etc/ntp.conf /etc/default/ssh /etc/avahi/avahi-daemon.conf /etc/avahi/hosts
/etc/powerdns /etc/default/pdns-recursor
/etc/ppp/ip-up.d/0000usepeerdns /etc/ppp/ip-down.d/0000usepeerdns"
for tmp in $DELETE; do
if [ -e ${tmp} ]; then
rm -rf ${tmp}
fi
done
# Remove logrotate items controlled via CLI and VyOS defaults
sed -i '/^\/var\/log\/messages$/d' /etc/logrotate.d/rsyslog
sed -i '/^\/var\/log\/auth.log$/d' /etc/logrotate.d/rsyslog
# Fix FRR pam.d "vtysh_pam" vtysh_pam: Failed in account validation T5110
if test -f /etc/pam.d/frr; then
if grep -q 'pam_rootok.so' /etc/pam.d/frr; then
sed -i -re 's/rootok/permit/' /etc/pam.d/frr
fi
fi
# Enable Cloud-init pre-configuration service
systemctl enable vyos-config-cloud-init.service
+# Enable Podman API
+systemctl enable podman.service
+
# Generate API GraphQL schema
/usr/libexec/vyos/services/api/graphql/generate/generate_schema.py
# Update XML cache
python3 /usr/lib/python3/dist-packages/vyos/xml_ref/update_cache.py
# Generate hardlinks for systemd units for multi VRF support
# as softlinks will fail in systemd:
# symlink target name type "ssh.service" does not match source, rejecting.
if [ ! -f /lib/systemd/system/ssh@.service ]; then
ln /lib/systemd/system/ssh.service /lib/systemd/system/ssh@.service
fi
# T4287 - as we have a non-signed kernel use the upstream wireless reulatory database
update-alternatives --set regulatory.db /lib/firmware/regulatory.db-upstream
diff --git a/smoketest/scripts/cli/test_container.py b/smoketest/scripts/cli/test_container.py
index 3dd97a175..5e33eba40 100755
--- a/smoketest/scripts/cli/test_container.py
+++ b/smoketest/scripts/cli/test_container.py
@@ -1,234 +1,252 @@
#!/usr/bin/env python3
#
# Copyright (C) 2021-2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
import glob
import json
from base_vyostest_shim import VyOSUnitTestSHIM
from ipaddress import ip_interface
from vyos.configsession import ConfigSessionError
from vyos.utils.process import cmd
from vyos.utils.process import process_named_running
base_path = ['container']
cont_image = 'busybox:stable' # busybox is included in vyos-build
PROCESS_NAME = 'conmon'
PROCESS_PIDFILE = '/run/vyos-container-{0}.service.pid'
busybox_image_path = '/usr/share/vyos/busybox-stable.tar'
def cmd_to_json(command):
c = cmd(command + ' --format=json')
data = json.loads(c)[0]
return data
class TestContainer(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestContainer, cls).setUpClass()
# Load image for smoketest provided in vyos-build
try:
cmd(f'cat {busybox_image_path} | sudo podman load')
except:
cls.skipTest(cls, reason='busybox image not available')
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
cls.cli_delete(cls, base_path)
@classmethod
def tearDownClass(cls):
super(TestContainer, cls).tearDownClass()
# Cleanup podman image
cmd(f'sudo podman image rm -f {cont_image}')
def tearDown(self):
self.cli_delete(base_path)
self.cli_commit()
# Ensure no container process remains
self.assertIsNone(process_named_running(PROCESS_NAME))
# Ensure systemd units are removed
units = glob.glob('/run/systemd/system/vyos-container-*')
self.assertEqual(units, [])
def test_basic(self):
cont_name = 'c1'
self.cli_set(['interfaces', 'ethernet', 'eth0', 'address', '10.0.2.15/24'])
self.cli_set(['protocols', 'static', 'route', '0.0.0.0/0', 'next-hop', '10.0.2.2'])
self.cli_set(['system', 'name-server', '1.1.1.1'])
self.cli_set(['system', 'name-server', '8.8.8.8'])
self.cli_set(base_path + ['name', cont_name, 'image', cont_image])
self.cli_set(base_path + ['name', cont_name, 'allow-host-networks'])
self.cli_set(base_path + ['name', cont_name, 'sysctl', 'parameter', 'kernel.msgmax', 'value', '4096'])
# commit changes
self.cli_commit()
pid = 0
with open(PROCESS_PIDFILE.format(cont_name), 'r') as f:
pid = int(f.read())
# Check for running process
self.assertEqual(process_named_running(PROCESS_NAME), pid)
# verify
tmp = cmd(f'sudo podman exec -it {cont_name} sysctl kernel.msgmax')
self.assertEqual(tmp, 'kernel.msgmax = 4096')
def test_cpu_limit(self):
cont_name = 'c2'
self.cli_set(base_path + ['name', cont_name, 'allow-host-networks'])
self.cli_set(base_path + ['name', cont_name, 'image', cont_image])
self.cli_set(base_path + ['name', cont_name, 'cpu-quota', '1.25'])
self.cli_commit()
pid = 0
with open(PROCESS_PIDFILE.format(cont_name), 'r') as f:
pid = int(f.read())
# Check for running process
self.assertEqual(process_named_running(PROCESS_NAME), pid)
def test_ipv4_network(self):
prefix = '192.0.2.0/24'
base_name = 'ipv4'
net_name = 'NET01'
self.cli_set(base_path + ['network', net_name, 'prefix', prefix])
for ii in range(1, 6):
name = f'{base_name}-{ii}'
self.cli_set(base_path + ['name', name, 'image', cont_image])
self.cli_set(base_path + ['name', name, 'network', net_name, 'address', str(ip_interface(prefix).ip + ii)])
# verify() - first IP address of a prefix can not be used by a container
with self.assertRaises(ConfigSessionError):
self.cli_commit()
tmp = f'{base_name}-1'
self.cli_delete(base_path + ['name', tmp])
self.cli_commit()
n = cmd_to_json(f'sudo podman network inspect {net_name}')
self.assertEqual(n['subnets'][0]['subnet'], prefix)
# skipt first container, it was never created
for ii in range(2, 6):
name = f'{base_name}-{ii}'
c = cmd_to_json(f'sudo podman container inspect {name}')
self.assertEqual(c['NetworkSettings']['Networks'][net_name]['Gateway'] , str(ip_interface(prefix).ip + 1))
self.assertEqual(c['NetworkSettings']['Networks'][net_name]['IPAddress'], str(ip_interface(prefix).ip + ii))
def test_ipv6_network(self):
prefix = '2001:db8::/64'
base_name = 'ipv6'
net_name = 'NET02'
self.cli_set(base_path + ['network', net_name, 'prefix', prefix])
for ii in range(1, 6):
name = f'{base_name}-{ii}'
self.cli_set(base_path + ['name', name, 'image', cont_image])
self.cli_set(base_path + ['name', name, 'network', net_name, 'address', str(ip_interface(prefix).ip + ii)])
# verify() - first IP address of a prefix can not be used by a container
with self.assertRaises(ConfigSessionError):
self.cli_commit()
tmp = f'{base_name}-1'
self.cli_delete(base_path + ['name', tmp])
self.cli_commit()
n = cmd_to_json(f'sudo podman network inspect {net_name}')
self.assertEqual(n['subnets'][0]['subnet'], prefix)
# skipt first container, it was never created
for ii in range(2, 6):
name = f'{base_name}-{ii}'
c = cmd_to_json(f'sudo podman container inspect {name}')
self.assertEqual(c['NetworkSettings']['Networks'][net_name]['IPv6Gateway'] , str(ip_interface(prefix).ip + 1))
self.assertEqual(c['NetworkSettings']['Networks'][net_name]['GlobalIPv6Address'], str(ip_interface(prefix).ip + ii))
def test_dual_stack_network(self):
prefix4 = '192.0.2.0/24'
prefix6 = '2001:db8::/64'
base_name = 'dual-stack'
net_name = 'net-4-6'
self.cli_set(base_path + ['network', net_name, 'prefix', prefix4])
self.cli_set(base_path + ['network', net_name, 'prefix', prefix6])
for ii in range(1, 6):
name = f'{base_name}-{ii}'
self.cli_set(base_path + ['name', name, 'image', cont_image])
self.cli_set(base_path + ['name', name, 'network', net_name, 'address', str(ip_interface(prefix4).ip + ii)])
self.cli_set(base_path + ['name', name, 'network', net_name, 'address', str(ip_interface(prefix6).ip + ii)])
# verify() - first IP address of a prefix can not be used by a container
with self.assertRaises(ConfigSessionError):
self.cli_commit()
tmp = f'{base_name}-1'
self.cli_delete(base_path + ['name', tmp])
self.cli_commit()
n = cmd_to_json(f'sudo podman network inspect {net_name}')
self.assertEqual(n['subnets'][0]['subnet'], prefix4)
self.assertEqual(n['subnets'][1]['subnet'], prefix6)
# skipt first container, it was never created
for ii in range(2, 6):
name = f'{base_name}-{ii}'
c = cmd_to_json(f'sudo podman container inspect {name}')
self.assertEqual(c['NetworkSettings']['Networks'][net_name]['IPv6Gateway'] , str(ip_interface(prefix6).ip + 1))
self.assertEqual(c['NetworkSettings']['Networks'][net_name]['GlobalIPv6Address'], str(ip_interface(prefix6).ip + ii))
self.assertEqual(c['NetworkSettings']['Networks'][net_name]['Gateway'] , str(ip_interface(prefix4).ip + 1))
self.assertEqual(c['NetworkSettings']['Networks'][net_name]['IPAddress'] , str(ip_interface(prefix4).ip + ii))
def test_uid_gid(self):
cont_name = 'uid-test'
gid = '100'
uid = '1001'
self.cli_set(base_path + ['name', cont_name, 'allow-host-networks'])
self.cli_set(base_path + ['name', cont_name, 'image', cont_image])
self.cli_set(base_path + ['name', cont_name, 'gid', gid])
# verify() - GID can only be set if UID is set
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(base_path + ['name', cont_name, 'uid', uid])
self.cli_commit()
# verify
tmp = cmd(f'sudo podman exec -it {cont_name} id -u')
self.assertEqual(tmp, uid)
tmp = cmd(f'sudo podman exec -it {cont_name} id -g')
self.assertEqual(tmp, gid)
+ def test_api_socket(self):
+ base_name = 'api-test'
+ container_list = range(1, 5)
+
+ for ii in container_list:
+ name = f'{base_name}-{ii}'
+ self.cli_set(base_path + ['name', name, 'image', cont_image])
+ self.cli_set(base_path + ['name', name, 'allow-host-networks'])
+
+ self.cli_commit()
+
+ # Query API about running containers
+ tmp = cmd("sudo curl --unix-socket /run/podman/podman.sock -H 'content-type: application/json' -sf http://localhost/containers/json")
+ tmp = json.loads(tmp)
+
+ # We expect the same amount of containers from the API that we started above
+ self.assertEqual(len(container_list), len(tmp))
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/systemd/podman.service b/src/systemd/podman.service
new file mode 100644
index 000000000..20a16304b
--- /dev/null
+++ b/src/systemd/podman.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=Podman API Service
+Requires=podman.socket
+After=podman.socket
+Documentation=man:podman-system-service(1)
+StartLimitIntervalSec=0
+
+[Service]
+Delegate=true
+Type=exec
+KillMode=process
+Environment=LOGGING="--log-level=info"
+ExecStart=/usr/bin/podman $LOGGING system service
+
+[Install]
+WantedBy=default.target
diff --git a/src/systemd/podman.socket b/src/systemd/podman.socket
new file mode 100644
index 000000000..397058ee4
--- /dev/null
+++ b/src/systemd/podman.socket
@@ -0,0 +1,10 @@
+[Unit]
+Description=Podman API Socket
+Documentation=man:podman-system-service(1)
+
+[Socket]
+ListenStream=%t/podman/podman.sock
+SocketMode=0660
+
+[Install]
+WantedBy=sockets.target
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Oct 17, 12:54 AM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4416745
Default Alt Text
(20 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment