diff --git a/Cargo.lock b/Cargo.lock index a4b843b4d..3eb894328 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1280,6 +1280,7 @@ dependencies = [ "kanidmd_core", "profiles", "reqwest", + "sd-notify", "serde", "sketching", "tikv-jemallocator", @@ -4345,6 +4346,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sd-notify" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "621e3680f3e07db4c9c2c3fb07c6223ab2fab2e54bd3c04c3ae037990f428c32" + [[package]] name = "security-framework" version = "2.9.2" diff --git a/Cargo.toml b/Cargo.toml index bd0ca5f94..cd041c444 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,6 +122,7 @@ scim_proto = "^0.2.1" # scim_proto = { path = "../scim/proto", version = "^0.2.1" } # scim_proto = { git = "https://github.com/kanidm/scim.git", version = "0.1.1" } +sd-notify = "^0.4.1" selinux = "^0.4.1" serde = "^1.0.174" serde_cbor = { version = "0.12.0-dev", package = "serde_cbor_2" } diff --git a/examples/server.toml b/examples/server.toml index efd404aa2..0506c331b 100644 --- a/examples/server.toml +++ b/examples/server.toml @@ -1,46 +1,64 @@ -# The webserver bind address. Will use HTTPS if tls_* is provided. +# The webserver bind address. Requires TLS certificates. +# If the port is set to 443 you may require the +# NET_BIND_SERVICE capability. # Defaults to "127.0.0.1:8443" bindaddress = "[::]:443" # -# The read-only ldap server bind address. The server will use LDAPS if tls_* is provided. +# The read-only ldap server bind address. Requires +# TLS certificates. If set to 636 you may require +# the NET_BIND_SERVICE capability. # Defaults to "" (disabled) # ldapbindaddress = "[::]:636" # -# The path to the kanidm database. -db_path = "/var/lib/kanidm/kanidm.db" +# HTTPS requests can be reverse proxied by a loadbalancer. +# To preserve the original IP of the caller, these systems +# will often add a header such as "Forwarded" or +# "X-Forwarded-For". If set to true, then this header is +# respected as the "authoritative" source of the IP of the +# connected client. If you are not using a load balancer +# then you should leave this value as default. +# Defaults to false +# trust_x_forward_for = false # -# If you have a known filesystem, kanidm can tune database operations to match. Valid choices are: +# The path to the kanidm database. +db_path = "/var/lib/private/kanidm/kanidm.db" +# +# If you have a known filesystem, kanidm can tune database +# to match. Valid choices are: # [zfs, other] -# If you are unsure about this leave it as the default (other). After changing this +# If you are unsure about this leave it as the default +# (other). After changing this # value you must run a vacuum task. # - zfs: -# * sets database pagesize to 64k. You must set recordsize=64k on the zfs filesystem. +# * sets database pagesize to 64k. You must set +# recordsize=64k on the zfs filesystem. # - other: -# * sets database pagesize to 4k, matching most filesystems block sizes. +# * sets database pagesize to 4k, matching most +# filesystems block sizes. # db_fs_type = "zfs" # -# The number of entries to store in the in-memory cache. Minimum value is 256. If unset +# The number of entries to store in the in-memory cache. +# Minimum value is 256. If unset # an automatic heuristic is used to scale this. # db_arc_size = 2048 # # TLS chain and key in pem format. Both must be present -tls_chain = "/data/chain.pem" -tls_key = "/data/key.pem" +tls_chain = "/var/lib/private/kanidm/chain.pem" +tls_key = "/var/lib/private/kanidm/key.pem" # # The log level of the server. May be one of info, debug, trace # -# NOTE: this is overridden by environment variables -# +# NOTE: this is overridden by environment variables at runtime # Defaults to "info" # log_level = "info" - +# # The DNS domain name of the server. This is used in a # number of security-critical contexts # such as webauthn, so it *must* match your DNS # hostname. It is used to create # security principal names such as `william@idm.example.com` # so that in a (future) -# trust configuration it is possible to have unique Service +# trust configuration it is possible to have unique Security # Principal Names (spns) throughout the topology. # ⚠️ WARNING ⚠️ # Changing this value WILL break many types of registered @@ -50,48 +68,44 @@ tls_key = "/data/key.pem" # `kanidmd domain_name_change` immediately after. domain = "idm.example.com" # -# The origin for webauthn. This is the url to the server, with the port included if -# it is non-standard (any port except 443) -# origin = "https://idm.example.com" +# The origin for webauthn. This is the url to the server, +# with the port included if +# it is non-standard (any port except 443). This must match +# or be a descendent of the +# domain name you configure above. If these two items are +# not consistent, the server WILL refuse to start! +# origin = "https://idm.example.com" origin = "https://idm.example.com:8443" # -# The role of this server. This affects features available and how replication may interact. +# The role of this server. This affects available features +# and how replication may interact. # Valid roles are: # - WriteReplica -# This server provides all functionality of Kanidm. It allows authentication, writes, and +# This server provides all functionality of Kanidm. It +# allows authentication, writes, and # the web user interface to be served. # - WriteReplicaNoUI -# This server is the same as a write_replica, but does NOT offer the web user interface. +# This server is the same as a WriteReplica, but does NOT +# offer the web user interface. # - ReadOnlyReplica -# This server will not writes initiated by clients. It supports authentication and reads, -# and must have a replication agreement as a source of it's data. +# This server will not writes initiated by clients. It +# supports authentication and reads, +# and must have a replication agreement as a source of +# its data. # Defaults to "WriteReplica". # role = "WriteReplica" # -# This section if uncommented will enable online - automatic backups of your database. -# [online_backup] -# +[online_backup] # The path to the output folder for online backups -# Defaults to "" (no path set) -# path = "/var/lib/kanidm/backups/" -# -# The schedule to run online backups. All times are interpreted in UTC. -# The format of the cron expression is: -# +path = "/var/lib/private/kanidm/backups/" +# The schedule to run online backups (see https://crontab.guru/) +# every day at 22:00 UTC (default) +schedule = "00 22 * * *" +# four times a day at 3 minutes past the hour, every 6th hours +# schedule = "03 */6 * * *" +# We also support non standard cron syntax, with the following format: # sec min hour day of month month day of week year -# -# - to run a 6:09 pm every day. -# "0 9 6 * * * * " -# "0 9 6 * * * *" -# -# - to run at midnight daily -# @daily -# -# - to run every hour -# @hourly -# -# Defaults to "@daily" -# schedule = "@daily" +# (it's very similar to the standard cron syntax, it just allows to specify the seconds +# at the beginning and the year at the end) # Number of backups to keep (default 7) # versions = 7 - diff --git a/examples/server_container.toml b/examples/server_container.toml index 046643dca..467ef1e2b 100644 --- a/examples/server_container.toml +++ b/examples/server_container.toml @@ -1,12 +1,12 @@ -# The webserver bind address. Will use HTTPS if tls_* -# is provided. If set to 443 you may require the +# The webserver bind address. Requires TLS certificates. +# If the port is set to 443 you may require the # NET_BIND_SERVICE capability. # Defaults to "127.0.0.1:8443" bindaddress = "[::]:8443" # -# The read-only ldap server bind address. The server -# will use LDAPS if tls_* is provided. If set to 636 -# you may require the NET_BIND_SERVICE capability. +# The read-only ldap server bind address. Requires +# TLS certificates. If set to 636 you may require +# the NET_BIND_SERVICE capability. # Defaults to "" (disabled) # ldapbindaddress = "[::]:3636" # @@ -58,7 +58,7 @@ tls_key = "/data/key.pem" # hostname. It is used to create # security principal names such as `william@idm.example.com` # so that in a (future) -# trust configuration it is possible to have unique Service +# trust configuration it is possible to have unique Security # Principal Names (spns) throughout the topology. # ⚠️ WARNING ⚠️ # Changing this value WILL break many types of registered @@ -95,12 +95,12 @@ origin = "https://idm.example.com:8443" # Defaults to "WriteReplica". # role = "WriteReplica" # -# [online_backup] +[online_backup] # The path to the output folder for online backups -# path = "/var/lib/kanidm/backups/" +path = "/data/kanidm/backups/" # The schedule to run online backups (see https://crontab.guru/) # every day at 22:00 UTC (default) -# schedule = "00 22 * * *" +schedule = "00 22 * * *" # four times a day at 3 minutes past the hour, every 6th hours # schedule = "03 */6 * * *" # We also support non standard cron syntax, with the following format: @@ -109,4 +109,3 @@ origin = "https://idm.example.com:8443" # at the beginning and the year at the end) # Number of backups to keep (default 7) # versions = 7 -# diff --git a/platform/debian/systemd/kanidm-unixd-tasks.service b/platform/debian/systemd/kanidm-unixd-tasks.service index 352d9ebf5..4aabbb8eb 100644 --- a/platform/debian/systemd/kanidm-unixd-tasks.service +++ b/platform/debian/systemd/kanidm-unixd-tasks.service @@ -10,22 +10,23 @@ User=root Type=simple ExecStart=/usr/sbin/kanidm_unixd_tasks -ReadWritePaths=/home /var/run/kanidm-unixd - CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH -MemoryDenyWriteExecute=true +# SystemCallFilter=@aio @basic-io @chown @file-system @io-event @network-io @sync +ProtectSystem=strict +ReadWritePaths=/home /var/run/kanidm-unixd +RestrictAddressFamilies=AF_UNIX NoNewPrivileges=true +PrivateTmp=true PrivateDevices=true PrivateNetwork=true -PrivateTmp=true -ProtectClock=true -ProtectControlGroups=true ProtectHostname=true -ProtectKernelLogs=true -ProtectKernelModules=true +ProtectClock=true ProtectKernelTunables=true -ProtectSystem=strict -RestrictAddressFamilies=AF_UNIX +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +MemoryDenyWriteExecute=true [Install] WantedBy=multi-user.target + diff --git a/platform/debian/systemd/kanidm-unixd.service b/platform/debian/systemd/kanidm-unixd.service index 76ce71f9c..11b49d31c 100644 --- a/platform/debian/systemd/kanidm-unixd.service +++ b/platform/debian/systemd/kanidm-unixd.service @@ -7,12 +7,31 @@ After=chronyd.service ntpd.service network-online.target [Service] DynamicUser=yes +SupplementaryGroups=tss +UMask=0027 +CacheDirectory=kanidm-unixd +RuntimeDirectory=kanidm-unixd + Type=simple ExecStart=/usr/sbin/kanidm_unixd -CacheDirectory=kanidm-unixd -RuntimeDirectory=kanidm-unixd -UMask=0027 +# Implied by dynamic user. +# ProtectHome= +# ProtectSystem=strict +# ReadWritePaths=/var/run/kanidm-unixd /var/cache/kanidm-unixd + +# SystemCallFilter=@aio @basic-io @chown @file-system @io-event @network-io @sync +NoNewPrivileges=true +PrivateTmp=true +# We have to disable this to allow tpmrm0 access for tpm binding. +PrivateDevices=false +ProtectHostname=true +ProtectClock=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +MemoryDenyWriteExecute=true [Install] WantedBy=multi-user.target diff --git a/platform/debian/systemd/kanidmd.service b/platform/debian/systemd/kanidmd.service index c212b85ec..12c512fce 100644 --- a/platform/debian/systemd/kanidmd.service +++ b/platform/debian/systemd/kanidmd.service @@ -2,19 +2,35 @@ # systemctl edit kanidmd.service [Unit] -Description=Kanidm, the IDM for rustaceans -After=network-online.target -Wants=network-online.target +Description=Kanidm Identity Server +After=time-sync.target network-online.target +Wants=time-sync.target network-online.target +Before=radiusd.service [Service] -Type=simple - -ExecStart=/usr/sbin/kanidmd server --config=/etc/kanidm/server.toml -Restart=on-failure -RestartSec=15s -WorkingDirectory=/var/lib/kanidm +Type=notify DynamicUser=yes StateDirectory=kanidm +StateDirectoryMode=0750 +CacheDirectory=kanidmd +CacheDirectoryMode=0750 +RuntimeDirectory=kanidmd +RuntimeDirectoryMode=0755 +ExecStart=/usr/sbin/kanidmd server -c /etc/kanidm/server.toml + +AmbientCapabilities=CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_BIND_SERVICE + +NoNewPrivileges=true +PrivateTmp=true +PrivateDevices=true +ProtectHostname=true +ProtectClock=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectKernelLogs=true +ProtectControlGroups=true +MemoryDenyWriteExecute=true [Install] WantedBy=multi-user.target diff --git a/platform/opensuse/kanidm-unixd-tasks.service b/platform/opensuse/kanidm-unixd-tasks.service index 9bbe8078a..4aabbb8eb 100644 --- a/platform/opensuse/kanidm-unixd-tasks.service +++ b/platform/opensuse/kanidm-unixd-tasks.service @@ -1,8 +1,6 @@ -# Source: https://build.opensuse.org/package/view_file/home:firstyear:kanidm/kanidm/kanidm-unixd-tasks.service # You should not need to edit this file. Instead, use a drop-in file: # systemctl edit kanidm-unixd-tasks.service - [Unit] Description=Kanidm Local Tasks After=chronyd.service ntpd.service network-online.target kanidm-unixd.service diff --git a/platform/opensuse/kanidm-unixd.service b/platform/opensuse/kanidm-unixd.service index 4e591f899..846f6e6bc 100644 --- a/platform/opensuse/kanidm-unixd.service +++ b/platform/opensuse/kanidm-unixd.service @@ -1,4 +1,3 @@ -# Source: https://build.opensuse.org/package/view_file/home:firstyear:kanidm/kanidm/kanidm-unixd.service # You should not need to edit this file. Instead, use a drop-in file: # systemctl edit kanidm-unixd.service diff --git a/platform/opensuse/kanidmd.service b/platform/opensuse/kanidmd.service index 9bc7089b9..969d02baa 100644 --- a/platform/opensuse/kanidmd.service +++ b/platform/opensuse/kanidmd.service @@ -1,19 +1,26 @@ -# Source: https://build.opensuse.org/package/view_file/home:firstyear:kanidm/kanidm/kanidmd.service # You should not need to edit this file. Instead, use a drop-in file as described in: # /usr/lib/systemd/system/kanidmd.service.d/custom.conf [Unit] Description=Kanidm Identity Server -After=chronyd.service ntpd.service network-online.target +After=time-sync.target network-online.target +Wants=time-sync.target network-online.target Before=radiusd.service [Service] -Type=simple +Type=notify DynamicUser=yes -UMask=0027 StateDirectory=kanidm +StateDirectoryMode=0750 +CacheDirectory=kanidmd +CacheDirectoryMode=0750 +RuntimeDirectory=kanidmd +RuntimeDirectoryMode=0755 ExecStart=/usr/sbin/kanidmd server -c /etc/kanidm/server.toml +AmbientCapabilities=CAP_NET_BIND_SERVICE +CapabilityBoundingSet=CAP_NET_BIND_SERVICE + NoNewPrivileges=true PrivateTmp=true PrivateDevices=true diff --git a/server/daemon/Cargo.toml b/server/daemon/Cargo.toml index a0afa164f..11f9d30ef 100644 --- a/server/daemon/Cargo.toml +++ b/server/daemon/Cargo.toml @@ -33,6 +33,9 @@ tokio-util = { workspace = true, features = ["codec"] } toml = { workspace = true } is-terminal = "0.4.9" +[target.'cfg(target_os = "linux")'.dependencies] +sd-notify.workspace = true + [target.'cfg(target_family = "windows")'.dependencies] whoami = { workspace = true } diff --git a/server/daemon/src/main.rs b/server/daemon/src/main.rs index 589e5a7c8..b45f6ed3a 100644 --- a/server/daemon/src/main.rs +++ b/server/daemon/src/main.rs @@ -412,6 +412,10 @@ async fn main() -> ExitCode { let sctx = create_server_core(config, config_test).await; if !config_test { + // On linux, notify systemd. + #[cfg(target_os = "linux")] + let _ = sd_notify::notify(true, &[sd_notify::NotifyState::Ready]); + match sctx { Ok(mut sctx) => { loop {