Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #413 Added base_os.pam_duo #414

Merged
merged 5 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions rsconf/component/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,59 @@ def install_resource(self, name, j2_ctx, host_path=None):
)
return host_path

def install_resource2(
self,
basename,
host_d,
host_f=None,
access=None,
host_d_access=None,
):
"""Simpler version of `install_resource`

Resource `module_name/basename` will be installed in `host_d/basename` with
`access` permissions (if not None).

If either `access` or `host_d_access` is a str, it will be assumed to be the mode
for `install_access`.

Args:
basename (str): basename of resource to be installed
host_d (py.path or str): host directory
host_f (py.path or str): host basename or full path (if py.path)
access (dict or str): passed to `install_access`
host_d_access (dict or str): if not None, `install_access` and `install_directory`
"""
host_d = pkio.py_path(host_d)
if host_f is None:
host_f = host_d.join(basename)
elif isinstance(host_f, str):
host_f = host_d.join(host_f)
if host_d_access is not None:
if isinstance(host_d_access, str):
host_d_access = PKDict(mode=host_d_access)
self.install_access(**host_d_access)
assert (
access is not None
), f"host_d_access={host_d_access} requires access be set"
self.install_directory(host_d)
if access is not None:
if isinstance(access, str):
access = PKDict(mode=access)
self.install_access(**access)
return self.install_resource(
f"{self.module_name}/{basename}", self.j2_ctx, host_f
)

def install_rpm_key(self, rpm_key, channel=None):
robnagler marked this conversation as resolved.
Show resolved Hide resolved
self._write_binary(
self.j2_ctx.build.dst_d.join(rpm_key),
db.resource_path(
self.j2_ctx, f"{self.module_name}/{rpm_key}"
).read_binary(),
)
self.append_root_bash(f"rsconf_install_rpm_key '{rpm_key}'")

def install_secret_path(
self, filename, host_path, gen_secret=None, visibility=None
):
Expand Down
60 changes: 33 additions & 27 deletions rsconf/component/base_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from rsconf import component

_JOURNAL_CONF_D = pkio.py_path("/etc/systemd/journald.conf.d")
_SSHD_CONF_F = pkio.py_path("/etc/ssh/sshd_config")
_SSHD_CONF_D = pkio.py_path("/etc/ssh")


class T(component.T):
Expand All @@ -32,42 +32,35 @@ def internal_build_compile(self):
)
z.logical_volume_cmds = cmds
self.service_prepare([_JOURNAL_CONF_D], name="systemd-journald")
self.service_prepare([_SSHD_CONF_F.dirpath()], name="sshd")
self.service_prepare([_SSHD_CONF_D], name="sshd")

def internal_build_write(self):
jc = self.j2_ctx
z = jc.base_os
self._install_local_dirs(jc.rsconf_db.local_dirs)
self._install_local_files(jc.rsconf_db.local_files)
self.install_access(mode="700", owner=jc.rsconf_db.root_u)
self.install_directory(_JOURNAL_CONF_D)
self.install_access(mode="400")
self.install_resource(
"base_os/journald.conf",
jc,
_JOURNAL_CONF_D.join("99-rsconf.conf"),
)
self.install_resource(
"base_os/60-rsconf-base.conf",
jc,
"/etc/sysctl.d/60-rsconf-base.conf",
self.install_resource2(
"journald.conf",
_JOURNAL_CONF_D,
host_f="99-rsconf.conf",
access="400",
host_d_access=PKDict(mode="700", owner=jc.rsconf_db.root_u),
)
self.install_resource2("60-rsconf-base.conf", "/etc/sysctl.d")
if "pam_limits" in z:
# POSIT: /etc/security/limits.d/20-nproc.conf is the only file on CentOS 7
self.install_resource(
"base_os/pam_limits",
jc,
"/etc/security/limits.d/99-rsconf.conf",
self.reboot_on_change(
[
self.install_resource2(
"pam_limits",
"/etc/security/limits.d",
host_f="99-rsconf.conf",
),
],
)
self.reboot_on_change(["/etc/security/limits.d/99-rsconf.conf"])
self.install_resource(
"base_os/sshd_config",
jc,
_SSHD_CONF_F,
)
self.install_access(mode="444")
self.install_resource("base_os/hostname", jc, "/etc/hostname")
self.install_resource("base_os/motd", jc, "/etc/motd")
self.install_resource2("hostname", "/etc", access="444")
self.install_resource2("motd", "/etc")
self._pam_duo_and_sshd()
self.append_root_bash_with_main(jc)

def _install_local_dirs(self, values):
Expand Down Expand Up @@ -110,6 +103,19 @@ def _install_local_files(self, values):
# to overwrite a local file, and error will occur.
self.install_abspath(v._source, t, ignore_exists=True)

def _pam_duo_and_sshd(self):
jc = self.j2_ctx
z = jc.base_os
if "pam_duo" in z:
self.install_resource2("duosecurity.repo", "/etc/yum.repos.d", access="444")
self.install_rpm_key("gpg-pubkey-ff696172-62979e51")
self.append_root_bash("rsconf_yum_install duo_unix")
# These are read dynamically by sshd so don't need to be watched files
self.install_resource2("pam_duo.conf", "/etc/duo", access="400")
self.install_resource2("pam_duo_sshd", "/etc/pam.d", host_f="sshd")
# Must be after pam_duo in case duo is installed so that sshd is not broken
self.install_resource2("sshd_config", _SSHD_CONF_D, access="400")

def _sorted_logical_volumes(self, vg):
res = []
for k, v in vg.logical_volumes.items():
Expand Down
2 changes: 1 addition & 1 deletion rsconf/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def resource_path(hdb, filename):
res = p.join(filename)
if res.check():
return res
return pkresource.filename(filename)
return pkresource.file_path(filename)


def secret_path(hdb, filename, visibility=None, qualifier=None, directory=False):
Expand Down
5 changes: 5 additions & 0 deletions rsconf/package_data/base_os/duosecurity.repo.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[duosecurity]
name=Duo Security Repository
baseurl=https://pkg.duosecurity.com/CentOS/$releasever/$basearch
enabled=1
gpgcheck=1
53 changes: 53 additions & 0 deletions rsconf/package_data/base_os/gpg-pubkey-ff696172-62979e51
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)

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
=KqQg
-----END PGP PUBLIC KEY BLOCK-----

7 changes: 7 additions & 0 deletions rsconf/package_data/base_os/pam_duo.conf.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[duo]
ikey={{ base_os.pam_duo.ikey }}
skey={{ base_os.pam_duo.skey }}
host={{ base_os.pam_duo.host }}
groups=*,!root
autopush=yes
pushinfo=yes
26 changes: 26 additions & 0 deletions rsconf/package_data/base_os/pam_duo_sshd.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#%PAM-1.0
auth required pam_sepermit.so
{# removed
auth substack password-auth
added next three lines
#}
auth required pam_env.so
auth sufficient pam_duo.so
auth required pam_deny.so
auth include postlogin
# Used with polkit to reauthorize users in remote sessions
-auth optional pam_reauthorize.so prepare
account required pam_nologin.so
account include password-auth
password include password-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open env_params
session required pam_namespace.so
session optional pam_keyinit.so force revoke
session include password-auth
session include postlogin
# Used with polkit to reauthorize users in remote sessions
-session optional pam_reauthorize.so prepare
17 changes: 10 additions & 7 deletions rsconf/package_data/base_os/sshd_config.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,18 @@ SyslogFacility AUTHPRIV
#LogLevel INFO

# Authentication:
{% if 'pam_duo' in base_os and base_os.pam_duo -%}
AuthenticationMethods publickey,keyboard-interactive
PermitRootLogin yes
ChallengeResponseAuthentication yes
PasswordAuthentication no
{% else -%}
PermitRootLogin without-password
ChallengeResponseAuthentication no
PasswordAuthentication yes
{% endif %}

#LoginGraceTime 2m
PermitRootLogin without-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
Expand All @@ -70,14 +79,8 @@ AuthorizedKeysFile .ssh/authorized_keys
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication yes
#PermitEmptyPasswords no

# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
ChallengeResponseAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
Expand Down
14 changes: 14 additions & 0 deletions rsconf/package_data/rsconf/rsconf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,20 @@ rsconf_install_perl_rpm() {
rsconf_service_file_changed "$rpm_file"
}

rsconf_install_rpm_key() {
# installs a custom rpm_key if not already installed
declare rpm_key=$1
if rpm -q "$rpm_key" &> /dev/null; then
return
fi
install_download "$rpm_key" > "$tmp"
robnagler marked this conversation as resolved.
Show resolved Hide resolved
if [[ ! $(file "$tmp" 2>/dev/null) =~ public.key ]]; then
install_err "$rpm_key: not found or not a valid rpm key"
fi
rpm --import "$tmp"
rm -f "$tmp"
}

rsconf_install_symlink() {
declare old=$1
declare new=$2
Expand Down
4 changes: 4 additions & 0 deletions tests/pkcli/build_data/1.in/db/000.yml
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ host:
# This host never installed, just for testing build
v9.radia.run:
base_os:
pam_duo:
ikey: sample-ikey
skey: sample-skey
host: sample-host.duosecurity.com
pam_limits:
nproc: 9999
base_users:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ rsconf_install_directory '/etc/systemd/journald.conf.d'
rsconf_install_access '400' 'root' 'root'
rsconf_install_file '/etc/systemd/journald.conf.d/99-rsconf.conf' '9556d6ace0f4113eed37ec4bb5225de1'
rsconf_install_file '/etc/sysctl.d/60-rsconf-base.conf' 'da732edac738b7aeda84e28eb516c99b'
rsconf_install_file '/etc/ssh/sshd_config' '74e16725821ffa2522ea8b65d6371d6c'
rsconf_install_access '444' 'root' 'root'
rsconf_install_file '/etc/hostname' 'f771df0d08c80cd35fb1108d0ef190b1'
rsconf_install_file '/etc/motd' '6bf408e65fc8387235735f3caebd3593'
rsconf_install_access '400' 'root' 'root'
rsconf_install_file '/etc/ssh/sshd_config' 'df36edac5e890beaa30eff7e6810afbb'
base_os_main
}
#!/bin/bash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ SyslogFacility AUTHPRIV
#LogLevel INFO

# Authentication:
PermitRootLogin without-password
ChallengeResponseAuthentication no
PasswordAuthentication yes

#LoginGraceTime 2m
PermitRootLogin without-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
Expand All @@ -62,14 +64,8 @@ AuthorizedKeysFile .ssh/authorized_keys
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication yes
#PermitEmptyPasswords no

# Change to no to disable s/key passwords
#ChallengeResponseAuthentication yes
ChallengeResponseAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ rsconf_install_directory '/etc/systemd/journald.conf.d'
rsconf_install_access '400' 'root' 'root'
rsconf_install_file '/etc/systemd/journald.conf.d/99-rsconf.conf' '9556d6ace0f4113eed37ec4bb5225de1'
rsconf_install_file '/etc/sysctl.d/60-rsconf-base.conf' 'da732edac738b7aeda84e28eb516c99b'
rsconf_install_file '/etc/ssh/sshd_config' '74e16725821ffa2522ea8b65d6371d6c'
rsconf_install_access '444' 'root' 'root'
rsconf_install_file '/etc/hostname' '7ef25e6de321777e3a7ebd514c666563'
rsconf_install_file '/etc/motd' '6bf408e65fc8387235735f3caebd3593'
rsconf_install_access '400' 'root' 'root'
rsconf_install_file '/etc/ssh/sshd_config' 'df36edac5e890beaa30eff7e6810afbb'
base_os_main
}
#!/bin/bash
Expand Down
Loading