Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion conf.example/adsys.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ global_trust_dir: /usr/local/share/ca-certificates
#ad_backend: sssd

# Certificate enrollment method: ldap (native Go, LDAP/RPC) or cepces (legacy Python/CEPCES).
# Defaults to cepces for backward compatibility with existing installations.
# If unset, defaults to cepces for backwards compatibility.
# New installations default to ldap.
#certificate_enrollment: cepces
Comment thread
adombeck marked this conversation as resolved.

# SSSd configuration
Expand Down
14 changes: 13 additions & 1 deletion debian/adsys.apport
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,21 @@
'''

import apport.hookutils
import apport.packaging
import re

def add_info(report):
apport.hookutils.attach_related_packages(report, ["sssd", "python3-samba"])
related_packages = ["sssd", "python3-samba"]

# python3-cepces is only Suggested (it lives in universe), so only
# attach it when it is actually installed on this system.
try:
apport.packaging.get_version("python3-cepces")
except ValueError:
pass
else:
related_packages.append("python3-cepces")

apport.hookutils.attach_related_packages(report, related_packages)
apport.hookutils.attach_journal_errors(report, 600)
report['Syslog'] = apport.hookutils.recent_syslog(re.compile("adsys"))
22 changes: 20 additions & 2 deletions debian/adsys.postinst
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
#!/bin/sh
set -e

CONFFILE=/etc/adsys.yaml

case "$1" in
configure)
pam-auth-update --package adsys
DEBIAN_FRONTEND=noninteractive pam-auth-update --package adsys

# For new installations (no previous version), set the LDAP-only
# certificate enrollment as default. Existing installations, and
# any file already present (e.g. hand-created by the admin before
# the first install, or left behind by a previous "remove"), are
# left untouched: existing installations keep the code default
# (cepces) for backward compatibility. The file is only ever
# removed on "dpkg --purge" (see postrm); a plain "remove" leaves
# it in place.
if [ -z "$2" ]; then
if [ ! -e "$CONFFILE" ] && [ ! -L "$CONFFILE" ]; then
cat > "$CONFFILE" << 'EOF'
# Certificate enrollment method: ldap (native Go, LDAP/RPC) or cepces (legacy Python/CEPCES).
certificate_enrollment: ldap
EOF
fi
fi
;;
esac

#DEBHELPER#

14 changes: 14 additions & 0 deletions debian/adsys.postrm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh
set -e

case "$1" in
purge)
# Only "dpkg --purge" removes the administrator's configuration;
# "remove" leaves it in place. There is no ucf/conffile machinery
# involved: the file is created directly by postinst (see there),
# so a plain rm is all that is needed here.
rm -f /etc/adsys.yaml
;;
esac

#DEBHELPER#
3 changes: 2 additions & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Architecture: any
Built-Using: ${misc:Built-Using},
Depends: ${shlibs:Depends},
${misc:Depends},
ca-certificates,
python3,
python3-samba,
samba-dsdb-modules,
Expand All @@ -45,8 +46,8 @@ Depends: ${shlibs:Depends},
Recommends: ${misc:Recommends},
ubuntu-advantage-desktop-daemon,
Suggests: curlftpfs,
ubuntu-proxy-manager,
python3-cepces,
ubuntu-proxy-manager,
Description: ${source:Synopsis}
${source:Extended-Description}

Expand Down
86 changes: 84 additions & 2 deletions debian/copyright
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,30 @@ Files: vendor/charm.land/*
Copyright: 2020-2026 Charmbracelet, Inc.
License: Expat

Files: vendor/github.com/Azure/*
Copyright: 2016 Microsoft
License: Expat

Files: vendor/github.com/Azure/go-ntlmssp/.golangci.yml
vendor/github.com/Azure/go-ntlmssp/authenticate_message.go
vendor/github.com/Azure/go-ntlmssp/authheader.go
vendor/github.com/Azure/go-ntlmssp/avids.go
vendor/github.com/Azure/go-ntlmssp/challenge_message.go
vendor/github.com/Azure/go-ntlmssp/messageheader.go
vendor/github.com/Azure/go-ntlmssp/negotiate_flags.go
vendor/github.com/Azure/go-ntlmssp/negotiate_message.go
vendor/github.com/Azure/go-ntlmssp/negotiator.go
vendor/github.com/Azure/go-ntlmssp/nlmp.go
vendor/github.com/Azure/go-ntlmssp/unicode.go
vendor/github.com/Azure/go-ntlmssp/varfield.go
vendor/github.com/Azure/go-ntlmssp/version.go
Copyright: Microsoft Corporation.
License: Expat

Files: vendor/github.com/Azure/go-ntlmssp/internal/*
Copyright: 2009 The Go Authors.
License: Expat

Files: vendor/github.com/alecthomas/*
Copyright: 2017 Alec Thomas
License: Expat
Expand Down Expand Up @@ -130,6 +154,20 @@ Copyright: 2012 The Go Authors.
fsnotify Authors.
License: BSD-3-clause

Files: vendor/github.com/geoffgarside/*
Copyright: 2009 The Go Authors.
License: BSD-3-clause

Files: vendor/github.com/go-asn1-ber/*
Copyright: 2011-2015 Michael Mitton () <mmitton@gmail.com>
2015-2016 go-asn1-ber Authors
License: Expat

Files: vendor/github.com/go-ldap/*
Copyright: 2011-2015 Michael Mitton () <mmitton@gmail.com>
2015-2024 go-ldap Authors
License: Expat

Files: vendor/github.com/go-viper/*
Copyright: 2013 Mitchell Hashimoto
License: Expat
Expand All @@ -154,9 +192,28 @@ Files: vendor/github.com/gorilla/*
Copyright: 2012-2023 The Gorilla Authors.
License: BSD-3-clause

Files: vendor/github.com/hashicorp/*
Copyright: 2015-2022 HashiCorp, Inc.
License: UNKNOWN

Files: vendor/github.com/inconshreveable/*
License: Apache-2.0

Files: vendor/github.com/indece-official/*
Copyright: 2019 indece
License: Expat

Files: vendor/github.com/indece-official/go-ebcdic/ebcdic.go
Copyright: 2019 indece UG (haftungsbeschränkt)
License: Expat

Files: vendor/github.com/jcmturner/*
License: Apache-2.0

Files: vendor/github.com/jcmturner/gofork/*
Copyright: 2009-2012 The Go Authors.
License: BSD-3-clause

Files: vendor/github.com/kardianos/*
Copyright: 2015-2019 Daniel Theophanes.
License: Zlib
Expand Down Expand Up @@ -227,6 +284,29 @@ Files: vendor/github.com/mvo5/*
Copyright: 2013-2019 Michael Vogt
License: UNKNOWN

Files: vendor/github.com/oiweiwei/*
Copyright: 2026 oiweiwei
License: Expat

Files: vendor/github.com/oiweiwei/go-smb2.fork/*
Copyright: 2016 Hiroshi Ioka.
License: BSD-2-clause

Files: vendor/github.com/oiweiwei/go-smb2.fork/all.go
vendor/github.com/oiweiwei/go-smb2.fork/filepath.go
Copyright: 2009 The Go Authors.
2016 Hiroshi Ioka.
License: BSD-3-clause

Files: vendor/github.com/oiweiwei/go-smb2.fork/internal/*
Copyright: 2009-2016 The Go Authors.
2016 Hiroshi Ioka.
License: BSD-3-clause

Files: vendor/github.com/oiweiwei/gokrb5.fork/*
Copyright: 2026 oiweiwei
License: Apache-2.0

Files: vendor/github.com/pelletier/*
Copyright: 2021-2023 Thomas Pelletier
License: Expat
Expand All @@ -243,6 +323,10 @@ Files: vendor/github.com/rivo/*
Copyright: 2019 Oliver Kuederle
License: Expat

Files: vendor/github.com/rs/*
Copyright: 2017 Olivier Poitrey
License: Expat

Files: vendor/github.com/russross/*
Copyright: 2011 Russ Ross <russ@russross.com>
License: BSD-2-clause
Expand Down Expand Up @@ -365,7 +449,6 @@ Files: vendor/go.yaml.in/yaml/v3/decode.go
vendor/go.yaml.in/yaml/v3/resolve.go
vendor/go.yaml.in/yaml/v3/sorter.go
vendor/go.yaml.in/yaml/v3/yaml.go
vendor/go.yaml.in/yaml/v3/NOTICE
Copyright: 2011-2019 Canonical Ltd
License: Apache-2.0

Expand Down Expand Up @@ -436,7 +519,6 @@ Files: vendor/gopkg.in/yaml.v3/decode.go
vendor/gopkg.in/yaml.v3/resolve.go
vendor/gopkg.in/yaml.v3/sorter.go
vendor/gopkg.in/yaml.v3/yaml.go
vendor/gopkg.in/yaml.v3/NOTICE
Copyright: 2011-2019 Canonical Ltd
License: Apache-2.0

Expand Down
7 changes: 7 additions & 0 deletions debian/tests/control
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@ Depends: @builddeps@
Test-Command: ./debian/tests/test sudo
Restrictions: allow-stderr, needs-root, skippable
Depends: @builddeps@

# Exercise packaging-level guarantees on the built binary package: the
# ca-certificates runtime dependency (M11) and the /etc/adsys.yaml
# lifecycle across fresh install, reinstall, remove and purge (M12).
Test-Command: ./debian/tests/packaging-smoke
Restrictions: allow-stderr, needs-root, skippable
Depends: @, ca-certificates
111 changes: 111 additions & 0 deletions debian/tests/packaging-smoke
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/bin/sh
# Packaging-level smoke test for the adsys binary package lifecycle.
#
# Covers:
# - M11: adsys directly depends on ca-certificates because the native LDAP
# certificate backend requires update-ca-certificates to be present.
# - M12: /etc/adsys.yaml is only ever created by postinst on a genuinely
# new install (dpkg's "most-recently-configured-version" is empty) that
# finds no file already in place, and is only ever removed by postrm on
# purge, never on a plain remove. So an administrator's edits, or any
# file already present before the very first install, always survive
# upgrades, reinstalls and remove.
set -e

CONFFILE=/etc/adsys.yaml
PKG=adsys

fail() {
echo "FAIL: $*" >&2
exit 1
}

# Resolve the exact package-under-test candidate version and pin every
# install/reinstall to it below, so this test always exercises the
# freshly built package and fails loudly instead of silently falling back
# to some other version an archive mirror configured in the testbed might
# offer.
CANDIDATE=$(apt-cache policy "$PKG" | awk '/Candidate:/ {print $2}')
[ -n "$CANDIDATE" ] && [ "$CANDIDATE" != "(none)" ] \
|| fail "could not determine an install candidate for $PKG"

assert_installed_version() {
INSTALLED=$(dpkg-query -W -f='${Version}' "$PKG" 2>/dev/null || true)
[ "$INSTALLED" = "$CANDIDATE" ] \
|| fail "expected $PKG $CANDIDATE to be installed, got '${INSTALLED:-<none>}'"
}

# Plain install: used both for a genuinely fresh/first configure and for
# reinstalling over a "config-files" (removed but not purged) package.
apt_install() {
apt-get install -y "${PKG}=${CANDIDATE}"
assert_installed_version
}

# Forces maintainer scripts to rerun even though the same version is
# already fully installed, to simulate an upgrade-like reconfigure.
apt_reinstall() {
apt-get install --reinstall -y "${PKG}=${CANDIDATE}"
assert_installed_version
}

echo "== M11: ca-certificates is a direct runtime dependency =="
command -v update-ca-certificates >/dev/null 2>&1 \
|| fail "update-ca-certificates is not available; ca-certificates dependency is missing or broken"
dpkg-query -W -f='${Depends}\n' "$PKG" | tr ',' '\n' | grep -qw 'ca-certificates' \
|| fail "$PKG no longer declares a direct dependency on ca-certificates"

echo "== M12: /etc/adsys.yaml lifecycle (candidate: $CANDIDATE) =="

# Fresh install: autopkgtest already installed the package under test, so
# the LDAP default must be in place.
assert_installed_version
[ -e "$CONFFILE" ] || fail "$CONFFILE is missing after a fresh install"
grep -q '^certificate_enrollment: ldap$' "$CONFFILE" \
|| fail "$CONFFILE does not contain the expected fresh-install default"

# Simulate an administrator edit, then an upgrade-like reconfigure of the
# already-installed package (most-recently-configured-version is set):
# local edits must survive untouched.
echo "# local-admin-edit-marker" >> "$CONFFILE"
apt_reinstall
grep -q 'local-admin-edit-marker' "$CONFFILE" \
|| fail "reinstalling $PKG discarded administrator edits to $CONFFILE"

# Plain remove must keep the conffile around (postrm only acts on purge).
apt-get remove -y "$PKG"
[ -e "$CONFFILE" ] || fail "'apt-get remove' deleted $CONFFILE; it must survive until purge"
grep -q 'local-admin-edit-marker' "$CONFFILE" \
|| fail "$CONFFILE lost its content across 'apt-get remove'"

# Installing again over the "config-files" state left by remove still has
# a most-recently-configured-version recorded by dpkg, so postinst must
# not touch the file at all.
apt_install
grep -q 'local-admin-edit-marker' "$CONFFILE" \
|| fail "reinstalling over the config-files state lost administrator edits"

# Purge must remove the file.
apt-get purge -y "$PKG"
[ ! -e "$CONFFILE" ] || fail "'apt-get purge' left $CONFFILE behind"

# A file created by an administrator after a purge, while the package is
# fully uninstalled, must be preserved by the next install: this is the
# genuinely-new-install-with-a-pre-existing-file case, and the only one
# where postinst's "file already present" guard actually has to trigger.
printf '# custom-pre-existing-marker\ncertificate_enrollment: cepces\n' > "$CONFFILE"
apt_install
grep -q 'custom-pre-existing-marker' "$CONFFILE" \
|| fail "installing over a file created after purge lost its content"
grep -q '^certificate_enrollment: cepces$' "$CONFFILE" \
|| fail "installing over a pre-existing file changed its certificate_enrollment setting"

# Leave the testbed in a clean, usable state: purge the custom file away
# and reinstall so a plain fresh LDAP default is in place again.
apt-get purge -y "$PKG"
apt_install
[ -e "$CONFFILE" ] || fail "$CONFFILE is missing after the final reinstall"
grep -q '^certificate_enrollment: ldap$' "$CONFFILE" \
|| fail "$CONFFILE does not contain the expected default after the final reinstall"

echo "OK"
3 changes: 2 additions & 1 deletion docs/explanation/certificates.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ Set the enrollment method in `/etc/adsys.yaml`:
certificate_enrollment: ldap # or "cepces"
```

* **Existing and new installations**: The default is `cepces` for backward compatibility. To use the native LDAP enrollment, add the setting above to your configuration file.
* **New installations**: The package creates `/etc/adsys.yaml` with `certificate_enrollment: ldap` when no configuration file exists yet.
* **Existing installations**: The default is `cepces` for backward compatibility. To switch to the native LDAP enrollment, add the setting above to your configuration file.

To ensure idempotency when applying the policy, enrollment state is persisted as a JSON file at `/var/lib/adsys/certs/state_$(hostname).<object-id>.json`, which contains information pertaining to the enrolled certificate(s).

Expand Down
2 changes: 1 addition & 1 deletion docs/how-to/certificates/configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This feature enables clients to seamlessly enroll for certificates from Active D
ADSys supports two certificate enrollment methods. Set the method in `/etc/adsys.yaml`:

```yaml
# Native Go implementation (LDAP/RPC)
# Native Go implementation (LDAP/RPC) — written to /etc/adsys.yaml on a new installation
certificate_enrollment: ldap

# Legacy Python/CEPCES implementation — used when the setting is absent
Expand Down
Loading
Loading