Page MenuHomeVyOS Platform

No OneTemporary

Size
20 KB
Referenced Files
None
Subscribers
None
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

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)

Event Timeline