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

Enable unprivileged containers #57

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ A well documented, tried and tested Samba Active Directory Domain Controller tha
* `INSECURELDAP` defaults to `false`. When set to true, it removes the secure LDAP requirement. While this is not recommended for production it is required for some LDAP tools. You can remove it later from the smb.conf file stored in the config directory.
* `MULTISITE` defaults to `false` and tells the container to connect to an OpenVPN site via an ovpn file with no password. For instance, if you have two locations where you run your domain controllers, they need to be able to interact. The VPN allows them to do that.
* `NOCOMPLEXITY` defaults to `false`. When set to `true` it removes password complexity requirements including `complexity, history-length, min-pwd-age, max-pwd-age`
* `IDLOWER` The minimum ID to use for user and group IDs within the DC ("XID"s). Defaults to 3000000.
* `IDUPPER` The maximum ID to use for user and group IDs within the DC ("XID"s). Defaults to 3000000.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* `IDUPPER` The maximum ID to use for user and group IDs within the DC ("XID"s). Defaults to 3000000.
* `IDUPPER` The maximum ID to use for user and group IDs within the DC ("XID"s). Defaults to 4000000.

* `ACLSTORAGE` If unspecified or set to `DEFAULT`, ACL information will be stored in the `security` namespace in extended attributes (xattr) as Samba normally does. If `userns` is specified, then ACL information will be stored in a `user` namespace in the xattrs instead of the `security` namespace. This is almost certainly necessary to run a container without "privileged" status or `CAP_SYS_ADMIN`, **However**, this means that the host kernel will not protect the _reading_ of the ACL data if direct filesystem access to the files is obtained (reading of ACL data is still controlled by Samba when accessed via CIFS). The implications of this are out of scope of this project, but you should research and understand the security implementations before using this feature. Currently `DEFAULT` and `userns` are the only supported options.

## Volumes for quick start
* `/etc/localtime:/etc/localtime:ro` - Sets the timezone to match the host
Expand Down Expand Up @@ -57,6 +60,13 @@ cp /path/to/my/ovpn/MYSITE.ovpn /data/docker/containers/samba/config/openvpn/doc
* Ensure client's are using corp.example.com as the search suffix
* If you're using a VPN, pay close attention to routes. You don't want to force all traffic through the VPN

## Running without `--privileged` (or `CAP_SYS_ADMIN`, etc.)

To run an unprivileged container, at a minimum you will almost certainly have to do two things:

1. Specify `IDLOWER` and `IDUPPER` to some range between 1 and 65536. Consider your host OS's `UID_MAX` configuration when choosing `IDLOWER`. A reasonable range to set for most unprivileged use is probably `IDLOWER=60001` and `IDUPPER=65535`, which gives you ~5000 users plus ~5000 groups—however this is far, far smaller a range than is provided by Samba by default (3000000 to 4000000 for 1M users and groups). The reason for this configuration is that to give unprivileged containers a set of UIDs that does not conflict with the host OS (e.g. so the container's `root` user with UID 0 is not the same as the host's `root` user with UID 0), the container runtime will usually allocate a block of UIDs and remap them to a different range on the host--and the block that is provided to the container is usually only 65536 user IDs. Therefore, attempting any operation on UIDs above 65536 simply fails. Even if your DC is not being used as a file server, DC-specific file stores (e.g. SYSVOL) need to have working permissions with working UIDs, so this has to be done. Note that for the same reasons, this same approach may be needed for Samba file servers running in unprivileged mode. There may be other ways to solve this using more complicated reconfiguration of your container runtime and/or ID mapping configuration, but this is outside of the scope of this project.

2. Specify `ACLSTORAGE` as `userns`. Normally, Samba stores Windows ACLs in eXtended Attributes (xattrs) in the `security` namespace--which is protected by the kernel and only allowed to be read and modified if the process has the proper rights. An unprivileged container will not be able to read or write these attributes. Therefore, this setting writes the ACL data in a namespace named `user` instead, which is not protected by the kernel. As mentioned above, this means that the ACL data is less protected than it otherwise would be and may be read by a person or process with lesser rights and direct access to the filesystem. Be aware of what this will do and what the risks are when using this setting.

## Enabling file sharing
While the Samba team does not recommend using a DC as a file server, it's understandable that some may wish to. Once the container is up and running and your `/data/docker/containers/samba/config/samba/smb.conf` file is set up after the first run, you can enable shares by shutting down the container, and making the following changes to the `smb.conf` file.
Expand Down
48 changes: 43 additions & 5 deletions init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ appSetup () {
JOIN=${JOIN:-false}
JOINSITE=${JOINSITE:-NONE}
MULTISITE=${MULTISITE:-false}
IDLOWER=${IDLOWER:-3000000}
IDUPPER=${IDUPPER:-4000000}
NOCOMPLEXITY=${NOCOMPLEXITY:-false}
INSECURELDAP=${INSECURELDAP:-false}
ACLSTORAGE=${ACLSTORAGE:-DEFAULT}
DNSFORWARDER=${DNSFORWARDER:-NONE}
HOSTIP=${HOSTIP:-NONE}
DOMAIN_DC=${DOMAIN_DC:-${DOMAIN_DC}}
Expand All @@ -35,6 +38,27 @@ appSetup () {
HOSTIP_OPTION=""
fi

# Set xattr options
if [[ "${ACLSTORAGE}" != "DEFAULT" ]]; then
# --use-xattrs removed in 4.9!
#ACLSTORAGE_OPTIONS=(--option="vfs objects = acl_xattr xattr_tdb" --use-xattrs=no)
# https://github.com/lxc/lxc/issues/2708#issuecomment-1865674625
ACLSTORAGE_OPTIONS=(
--option="vfs objects = dfs_samba4 acl_xattr xattr_tdb"
--option="acl_xattr:security_acl_name = user.NTACL"
)
#TODO: Add nfs4acl_xattr as another option?
# https://lists.samba.org/archive/samba/2021-February/234326.html
#ACLSTORAGE_OPTIONS=(
# --option="vfs objects = dfs_samba4 posixacl nfs4acl_xattr acl_xattr"
# --option="nfs4acl_xattr:encoding = nfs"
# --option="nfs4acl_xattr:default acl style = windows"
# --option="nfs4acl_xattr:xattr_name = user.nfs4_acl"
#)
else
ACLSTORAGE_OPTIONS=()
fi

# Set up samba
mv /etc/krb5.conf /etc/krb5.conf.orig
echo "[libdefaults]" > /etc/krb5.conf
Expand All @@ -48,12 +72,26 @@ appSetup () {
mv /etc/samba/smb.conf /etc/samba/smb.conf.orig
if [[ ${JOIN,,} == "true" ]]; then
if [[ ${JOINSITE} == "NONE" ]]; then
samba-tool domain join ${LDOMAIN} DC -U"${URDOMAIN}\administrator" --password="${DOMAINPASS}" --dns-backend=SAMBA_INTERNAL
samba-tool domain join ${LDOMAIN} DC -U"${URDOMAIN}\administrator" --password="${DOMAINPASS}" --dns-backend=SAMBA_INTERNAL \
"${ACLSTORAGE_OPTIONS[@]}" --option="idmap config * : range = ${IDLOWER}-${IDUPPER}"
else
samba-tool domain join ${LDOMAIN} DC -U"${URDOMAIN}\administrator" --password="${DOMAINPASS}" --dns-backend=SAMBA_INTERNAL --site=${JOINSITE}
samba-tool domain join ${LDOMAIN} DC -U"${URDOMAIN}\administrator" --password="${DOMAINPASS}" --dns-backend=SAMBA_INTERNAL --site=${JOINSITE} \
"${ACLSTORAGE_OPTIONS[@]}" --option="idmap config * : range = ${IDLOWER}-${IDUPPER}"
fi
else
samba-tool domain provision --use-rfc2307 --domain=${URDOMAIN} --realm=${UDOMAIN} --server-role=dc --dns-backend=SAMBA_INTERNAL --adminpass=${DOMAINPASS} ${HOSTIP_OPTION}
# https://github.com/lxc/lxc/issues/2708#issuecomment-473466062 ... -544 is BUILTIN\Administrators
printf '%s\n' \
"dn: CN=S-1-5-32-544"\
"cn: S-1-5-32-544"\
"objectClass: sidMap"\
"objectSid: S-1-5-32-544"\
"type: ID_TYPE_BOTH"\
"xidNumber: ${IDLOWER}"\
"distinguishedName: CN=S-1-5-32-544" >> /usr/share/samba/setup/idmap_init.ldif
sed -i "s/3000000/${IDLOWER}/g" /usr/share/samba/setup/idmap_init.ldif
sed -i "s/4000000/${IDUPPER}/g" /usr/share/samba/setup/idmap_init.ldif
samba-tool domain provision --use-rfc2307 --domain=${URDOMAIN} --realm=${UDOMAIN} --server-role=dc --dns-backend=SAMBA_INTERNAL --adminpass=${DOMAINPASS} ${HOSTIP_OPTION} \
"${ACLSTORAGE_OPTIONS[@]}" --option="idmap config * : range = ${IDLOWER}-${IDUPPER}"
if [[ ${NOCOMPLEXITY,,} == "true" ]]; then
samba-tool domain passwordsettings set --complexity=off
samba-tool domain passwordsettings set --history-length=0
Expand Down Expand Up @@ -128,7 +166,7 @@ fixDomainUsersGroup () {
echo "dn: CN=Domain Users,CN=Users,${DOMAIN_DC}
changetype: modify
add: gidNumber
gidNumber: 3000000" | ldbmodify -H /var/lib/samba/private/sam.ldb
gidNumber: $((IDLOWER + 1))" | ldbmodify -H /var/lib/samba/private/sam.ldb
net cache flush
fi
}
Expand Down Expand Up @@ -171,7 +209,7 @@ schemaIDGUID:: +8nFQ43rpkWTOgbCCcSkqA==" > /tmp/Sshpubkey.class.ldif
appStart () {
/usr/bin/supervisord > /var/log/supervisor/supervisor.log 2>&1 &
if [ "${1}" = "true" ]; then
echo "Sleeping 10 before checking on Domain Users of gid 3000000 and setting up sshPublicKey"
echo "Sleeping 10 before checking on Domain Users of gid $((IDLOWER + 1)) and setting up sshPublicKey"
sleep 10
fixDomainUsersGroup
setupSSH
Expand Down