URL: https://github.com/SSSD/sssd/pull/705 Author: jhrozek Title: #705: KCM: Add configurable quotas Action: synchronized
To pull the PR as Git branch: git remote add ghsssd https://github.com/SSSD/sssd git fetch ghsssd pull/705/head:pr705 git checkout pr705
From 9fd1cce377766e4c56b9e7d86bcaaa7d15341e4c Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Fri, 5 Oct 2018 13:17:14 +0200 Subject: [PATCH 1/7] MAN: Get rid of sssd-secrets reference Related: https://pagure.io/SSSD/sssd/issue/3685 There were some stray references to the secrets responder in the sssd-kcm manual page. --- src/man/sssd-kcm.8.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml index fff8b0a16d..90b9ad09c2 100644 --- a/src/man/sssd-kcm.8.xml +++ b/src/man/sssd-kcm.8.xml @@ -58,11 +58,9 @@ </listitem> <listitem> <para> - the SSSD implementation stores the ccaches in the SSSD - <citerefentry> - <refentrytitle>sssd-secrets</refentrytitle><manvolnum>5</manvolnum> - </citerefentry> - secrets store, allowing the ccaches to survive KCM server restarts or machine reboots. + the SSSD implementation stores the ccaches in a database, + typically located at <replaceable>/var/lib/sss/secrets</replaceable> + allowing the ccaches to survive KCM server restarts or machine reboots. </para> </listitem> </itemizedlist> From bab75a992b3a6414f9ee26b4aae6a849291bdc8b Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Fri, 30 Nov 2018 13:15:58 +0100 Subject: [PATCH 2/7] MAN: Document that it is enough to systemctl restart sssd-kcm.service lately Related: https://pagure.io/SSSD/sssd/issue/3862 We forgot to amend the man page after implementing the sssd-kcm service reload. --- src/man/sssd-kcm.8.xml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml index 90b9ad09c2..4e4aaa38ea 100644 --- a/src/man/sssd-kcm.8.xml +++ b/src/man/sssd-kcm.8.xml @@ -162,12 +162,17 @@ systemctl restart sssd-kcm.service <title>CONFIGURATION OPTIONS</title> <para> The KCM service is configured in the <quote>kcm</quote> - section of the sssd.conf file. Please note that currently, - is it not sufficient to restart the sssd-kcm service, because - the sssd configuration is only parsed and read to an internal - configuration database by the sssd service. Therefore you - must restart the sssd service if you change anything in the - <quote>kcm</quote> section of sssd.conf. + section of the sssd.conf file. Please note that because + the KCM service is typically socket-activated, it is + enough to just restart the <quote>sssd-kcm</quote> service + after changing options in the <quote>kcm</quote> section + of sssd.conf: + <programlisting> +systemctl restart sssd-kcm.service + </programlisting> + </para> + <para> + The KCM service is configured in the <quote>kcm</quote> For a detailed syntax reference, refer to the <quote>FILE FORMAT</quote> section of the <citerefentry> <refentrytitle>sssd.conf</refentrytitle> From a2d07b864ca14efee37fecc421a73460fa55ebb4 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Mon, 26 Nov 2018 13:44:08 +0100 Subject: [PATCH 3/7] SECRETS: Use different option names from secrets and KCM for quota options Related: https://pagure.io/SSSD/sssd/issue/3386 With the separate secrets responder, the quotas for the /secrets and /kcm hives were configurable in a sub-section of the [secrets] sssd.conf section using the same option -- the /secrets vs. /kcm distinction was made using the subsection name. With the standalone KCM responder writing directly to the database, it makes sense to have options with more descriptive names better suitable for the KCM usage. For that we need the options for secrets quotas and kcm quotas to be named differently. For now, the patch only passes the option name to sss_sec_get_quota() and sss_sec_get_hive_config() together with the default value in an instance of a new structure sss_sec_quota_opt. The secrets responder still uses the same option names for backwards compatibility. --- src/responder/secrets/secsrv.c | 70 ++++++++++++++++++++++++++-------- src/util/secrets/config.c | 40 +++++++++---------- src/util/secrets/secrets.h | 21 ++++++---- 3 files changed, 88 insertions(+), 43 deletions(-) diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c index 2de93dedc5..e783e231d3 100644 --- a/src/responder/secrets/secsrv.c +++ b/src/responder/secrets/secsrv.c @@ -47,6 +47,39 @@ static void adjust_global_quota(struct sec_ctx *sctx, static int sec_get_config(struct sec_ctx *sctx) { int ret; + struct sss_sec_quota_opt dfl_sec_nest_level = { + .opt_name = CONFDB_SEC_CONTAINERS_NEST_LEVEL, + .default_value = DEFAULT_SEC_CONTAINERS_NEST_LEVEL, + }; + struct sss_sec_quota_opt dfl_sec_max_secrets = { + .opt_name = CONFDB_SEC_MAX_SECRETS, + .default_value = DEFAULT_SEC_MAX_SECRETS, + }; + struct sss_sec_quota_opt dfl_sec_max_uid_secrets = { + .opt_name = CONFDB_SEC_MAX_UID_SECRETS, + .default_value = DEFAULT_SEC_MAX_UID_SECRETS, + }; + struct sss_sec_quota_opt dfl_sec_max_payload_size = { + .opt_name = CONFDB_SEC_MAX_PAYLOAD_SIZE, + .default_value = DEFAULT_SEC_MAX_PAYLOAD_SIZE, + }; + + struct sss_sec_quota_opt dfl_kcm_nest_level = { + .opt_name = CONFDB_SEC_CONTAINERS_NEST_LEVEL, + .default_value = DEFAULT_SEC_CONTAINERS_NEST_LEVEL, + }; + struct sss_sec_quota_opt dfl_kcm_max_secrets = { + .opt_name = CONFDB_SEC_MAX_SECRETS, + .default_value = DEFAULT_SEC_KCM_MAX_SECRETS, + }; + struct sss_sec_quota_opt dfl_kcm_max_uid_secrets = { + .opt_name = CONFDB_SEC_MAX_UID_SECRETS, + .default_value = DEFAULT_SEC_KCM_MAX_UID_SECRETS, + }; + struct sss_sec_quota_opt dfl_kcm_max_payload_size = { + .opt_name = CONFDB_SEC_MAX_PAYLOAD_SIZE, + .default_value = DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE, + }; ret = confdb_get_int(sctx->rctx->cdb, sctx->rctx->confdb_service_path, @@ -65,15 +98,12 @@ static int sec_get_config(struct sec_ctx *sctx) sctx->max_payload_size = 1; /* Read the global quota first -- this should be removed in a future release */ - /* Note that this sets the defaults for the sec_config quota to be used - * in sec_get_hive_config() - */ ret = sss_sec_get_quota(sctx->rctx->cdb, sctx->rctx->confdb_service_path, - DEFAULT_SEC_CONTAINERS_NEST_LEVEL, - DEFAULT_SEC_MAX_SECRETS, - DEFAULT_SEC_MAX_UID_SECRETS, - DEFAULT_SEC_MAX_PAYLOAD_SIZE, + &dfl_sec_nest_level, + &dfl_sec_max_secrets, + &dfl_sec_max_uid_secrets, + &dfl_sec_max_payload_size, &sctx->sec_config.quota); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, @@ -81,13 +111,23 @@ static int sec_get_config(struct sec_ctx *sctx) goto fail; } + /* Use the global quota values as defaults for the secrets/secrets section */ + dfl_sec_nest_level.default_value = \ + sctx->sec_config.quota.containers_nest_level; + dfl_sec_max_secrets.default_value = \ + sctx->sec_config.quota.max_secrets; + dfl_sec_max_uid_secrets.default_value = \ + sctx->sec_config.quota.max_uid_secrets; + dfl_sec_max_payload_size.default_value = \ + sctx->sec_config.quota.max_payload_size; + /* Read the per-hive configuration */ ret = sss_sec_get_hive_config(sctx->rctx->cdb, "secrets", - sctx->sec_config.quota.containers_nest_level, - sctx->sec_config.quota.max_secrets, - sctx->sec_config.quota.max_uid_secrets, - sctx->sec_config.quota.max_payload_size, + &dfl_sec_nest_level, + &dfl_sec_max_secrets, + &dfl_sec_max_uid_secrets, + &dfl_sec_max_payload_size, &sctx->sec_config); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, @@ -98,10 +138,10 @@ static int sec_get_config(struct sec_ctx *sctx) ret = sss_sec_get_hive_config(sctx->rctx->cdb, "kcm", - DEFAULT_SEC_CONTAINERS_NEST_LEVEL, - DEFAULT_SEC_KCM_MAX_SECRETS, - DEFAULT_SEC_KCM_MAX_UID_SECRETS, - DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE, + &dfl_kcm_nest_level, + &dfl_kcm_max_secrets, + &dfl_kcm_max_uid_secrets, + &dfl_kcm_max_payload_size, &sctx->kcm_config); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, diff --git a/src/util/secrets/config.c b/src/util/secrets/config.c index cb286121f4..f5dac0b21a 100644 --- a/src/util/secrets/config.c +++ b/src/util/secrets/config.c @@ -24,10 +24,10 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb, const char *section_config_path, - int default_max_containers_nest_level, - int default_max_num_secrets, - int default_max_num_uid_secrets, - int default_max_payload, + struct sss_sec_quota_opt *dfl_max_containers_nest_level, + struct sss_sec_quota_opt *dfl_max_num_secrets, + struct sss_sec_quota_opt *dfl_max_num_uid_secrets, + struct sss_sec_quota_opt *dfl_max_payload, struct sss_sec_quota *quota) { int ret; @@ -38,8 +38,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb, ret = confdb_get_int(cdb, section_config_path, - CONFDB_SEC_CONTAINERS_NEST_LEVEL, - default_max_containers_nest_level, + dfl_max_containers_nest_level->opt_name, + dfl_max_containers_nest_level->default_value, "a->containers_nest_level); if (ret != EOK) { @@ -51,8 +51,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb, ret = confdb_get_int(cdb, section_config_path, - CONFDB_SEC_MAX_SECRETS, - default_max_num_secrets, + dfl_max_num_secrets->opt_name, + dfl_max_num_secrets->default_value, "a->max_secrets); if (ret != EOK) { @@ -64,8 +64,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb, ret = confdb_get_int(cdb, section_config_path, - CONFDB_SEC_MAX_UID_SECRETS, - default_max_num_uid_secrets, + dfl_max_num_uid_secrets->opt_name, + dfl_max_num_uid_secrets->default_value, "a->max_uid_secrets); if (ret != EOK) { @@ -77,8 +77,8 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb, ret = confdb_get_int(cdb, section_config_path, - CONFDB_SEC_MAX_PAYLOAD_SIZE, - default_max_payload, + dfl_max_payload->opt_name, + dfl_max_payload->default_value, "a->max_payload_size); if (ret != EOK) { @@ -93,10 +93,10 @@ errno_t sss_sec_get_quota(struct confdb_ctx *cdb, errno_t sss_sec_get_hive_config(struct confdb_ctx *cdb, const char *hive_name, - int default_max_containers_nest_level, - int default_max_num_secrets, - int default_max_num_uid_secrets, - int default_max_payload, + struct sss_sec_quota_opt *dfl_max_containers_nest_level, + struct sss_sec_quota_opt *dfl_max_num_secrets, + struct sss_sec_quota_opt *dfl_max_num_uid_secrets, + struct sss_sec_quota_opt *dfl_max_payload, struct sss_sec_hive_config *hive_config) { int ret; @@ -122,10 +122,10 @@ errno_t sss_sec_get_hive_config(struct confdb_ctx *cdb, ret = sss_sec_get_quota(cdb, confdb_section, - default_max_containers_nest_level, - default_max_num_secrets, - default_max_num_uid_secrets, - default_max_payload, + dfl_max_containers_nest_level, + dfl_max_num_secrets, + dfl_max_num_uid_secrets, + dfl_max_payload, &hive_config->quota); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h index 01abfe5425..31164bd865 100644 --- a/src/util/secrets/secrets.h +++ b/src/util/secrets/secrets.h @@ -47,6 +47,11 @@ struct sss_sec_ctx; struct sss_sec_req; +struct sss_sec_quota_opt { + const char *opt_name; + int default_value; +}; + struct sss_sec_quota { int max_secrets; int max_uid_secrets; @@ -98,18 +103,18 @@ bool sss_sec_req_is_list(struct sss_sec_req *req); errno_t sss_sec_get_quota(struct confdb_ctx *cdb, const char *section_config_path, - int default_max_containers_nest_level, - int default_max_num_secrets, - int default_max_num_uid_secrets, - int default_max_payload, + struct sss_sec_quota_opt *dfl_max_containers_nest_level, + struct sss_sec_quota_opt *dfl_max_num_secrets, + struct sss_sec_quota_opt *dfl_max_num_uid_secrets, + struct sss_sec_quota_opt *dfl_max_payload, struct sss_sec_quota *quota); errno_t sss_sec_get_hive_config(struct confdb_ctx *cdb, const char *hive_name, - int default_max_containers_nest_level, - int default_max_num_secrets, - int default_max_num_uid_secrets, - int default_max_payload, + struct sss_sec_quota_opt *dfl_max_containers_nest_level, + struct sss_sec_quota_opt *dfl_max_num_secrets, + struct sss_sec_quota_opt *dfl_max_num_uid_secrets, + struct sss_sec_quota_opt *dfl_max_payload, struct sss_sec_hive_config *hive_config); #endif /* __SECRETS_H_ */ From a02e72cf85f89df962d52fd3ab78941f009d19dd Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Fri, 30 Nov 2018 13:34:22 +0100 Subject: [PATCH 4/7] SECRETS: Don't limit the global number of ccaches Related: https://pagure.io/SSSD/sssd/issue/3386 In the KCM context, the global number of ccaches would limit the number of users who can store their ccaches in the KCM deamon. In more detail, the options have the following semantics with KCM: - DEFAULT_SEC_KCM_MAX_SECRETS - global number of secrets, would cover both how many ccaches can a user store, but this is better served with DEFAULT_SEC_KCM_MAX_UID_SECRETS - DEFAULT_SEC_KCM_MAX_UID_SECRETS - how many 'principals' can a user kinit with - DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE - the payload size of service tickets With the above in mind, I think the most important limits are max_uid_secrets to limit and the payload size to constraint how much space can a user occupy and it doesn't make much sense to limit the global quota. --- src/util/secrets/secrets.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h index 31164bd865..9cf3975162 100644 --- a/src/util/secrets/secrets.h +++ b/src/util/secrets/secrets.h @@ -39,7 +39,7 @@ * but the secret size must be large because one secret in the /kcm * hive holds the whole ccache which consists of several credentials */ -#define DEFAULT_SEC_KCM_MAX_SECRETS 256 +#define DEFAULT_SEC_KCM_MAX_SECRETS 0 /* unlimited */ #define DEFAULT_SEC_KCM_MAX_UID_SECRETS 64 #define DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE 65536 From 122152711c8c848af980f24fff9e3f567eab2bef Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Wed, 28 Nov 2018 21:24:08 +0100 Subject: [PATCH 5/7] KCM: Pass confdb context to the ccache db initialization Resolves: https://pagure.io/SSSD/sssd/issue/3386 The libsecrets back end needs to read the quota options from confdb, therefore it needs to know the section and access the confdb handle. These parameters are unused for other ccache back end types, but they are harmless and IMO it makes more sense to keep the ccache back end abstract. --- src/responder/kcm/kcm.c | 14 ++++++++++++-- src/responder/kcm/kcmsrv_ccache.c | 4 +++- src/responder/kcm/kcmsrv_ccache.h | 2 ++ src/responder/kcm/kcmsrv_ccache_be.h | 4 +++- src/responder/kcm/kcmsrv_ccache_mem.c | 4 +++- src/responder/kcm/kcmsrv_ccache_secdb.c | 6 +++--- src/responder/kcm/kcmsrv_ccache_secrets.c | 4 +++- 7 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c index 005dd168f8..045c7801fa 100644 --- a/src/responder/kcm/kcm.c +++ b/src/responder/kcm/kcm.c @@ -170,6 +170,8 @@ static int kcm_data_destructor(void *ptr) static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct confdb_ctx *cdb, + const char *confdb_service_path, enum kcm_ccdb_be cc_be) { struct kcm_resp_ctx *kcm_data; @@ -181,7 +183,11 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx, return NULL; } - kcm_data->db = kcm_ccdb_init(kcm_data, ev, cc_be); + kcm_data->db = kcm_ccdb_init(kcm_data, + ev, + cdb, + confdb_service_path, + cc_be); if (kcm_data->db == NULL) { talloc_free(kcm_data); return NULL; @@ -235,7 +241,11 @@ static int kcm_process_init(TALLOC_CTX *mem_ctx, goto fail; } - kctx->kcm_data = kcm_data_setup(kctx, ev, kctx->cc_be); + kctx->kcm_data = kcm_data_setup(kctx, + ev, + kctx->rctx->cdb, + kctx->rctx->confdb_service_path, + kctx->cc_be); if (kctx->kcm_data == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing responder data\n"); diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c index e7800662ac..085cc4464c 100644 --- a/src/responder/kcm/kcmsrv_ccache.c +++ b/src/responder/kcm/kcmsrv_ccache.c @@ -229,6 +229,8 @@ struct sss_iobuf *kcm_cred_get_creds(struct kcm_cred *crd) struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct confdb_ctx *cdb, + const char *confdb_service_path, enum kcm_ccdb_be cc_be) { errno_t ret; @@ -270,7 +272,7 @@ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, return NULL; } - ret = ccdb->ops->init(ccdb); + ret = ccdb->ops->init(ccdb, cdb, confdb_service_path); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize ccache database\n"); talloc_free(ccdb); diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h index 0fd33325f0..199b75b16c 100644 --- a/src/responder/kcm/kcmsrv_ccache.h +++ b/src/responder/kcm/kcmsrv_ccache.h @@ -125,6 +125,8 @@ struct kcm_ccdb; */ struct kcm_ccdb *kcm_ccdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + struct confdb_ctx *cdb, + const char *confdb_service_path, enum kcm_ccdb_be cc_be); /* diff --git a/src/responder/kcm/kcmsrv_ccache_be.h b/src/responder/kcm/kcmsrv_ccache_be.h index 7315f64353..166af3a764 100644 --- a/src/responder/kcm/kcmsrv_ccache_be.h +++ b/src/responder/kcm/kcmsrv_ccache_be.h @@ -30,7 +30,9 @@ #include "responder/kcm/kcmsrv_ccache.h" typedef errno_t -(*ccdb_init_fn)(struct kcm_ccdb *db); +(*ccdb_init_fn)(struct kcm_ccdb *db, + struct confdb_ctx *cdb, + const char *confdb_service_path); typedef struct tevent_req * (*ccdb_nextid_send_fn)(TALLOC_CTX *mem_ctx, diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c index 38bc2050d9..35955b2f4a 100644 --- a/src/responder/kcm/kcmsrv_ccache_mem.c +++ b/src/responder/kcm/kcmsrv_ccache_mem.c @@ -151,7 +151,9 @@ static int ccwrap_destructor(void *ptr) return 0; } -static errno_t ccdb_mem_init(struct kcm_ccdb *db) +static errno_t ccdb_mem_init(struct kcm_ccdb *db, + struct confdb_ctx *cdb, + const char *confdb_service_path) { struct ccdb_mem *memdb = NULL; diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c index a61d7b15be..5ccb21aa73 100644 --- a/src/responder/kcm/kcmsrv_ccache_secdb.c +++ b/src/responder/kcm/kcmsrv_ccache_secdb.c @@ -520,7 +520,9 @@ static errno_t secdb_get_cc(TALLOC_CTX *mem_ctx, return ret; } -static errno_t ccdb_secdb_init(struct kcm_ccdb *db) +static errno_t ccdb_secdb_init(struct kcm_ccdb *db, + struct confdb_ctx *cdb, + const char *confdb_service_path) { struct ccdb_secdb *secdb = NULL; errno_t ret; @@ -530,8 +532,6 @@ static errno_t ccdb_secdb_init(struct kcm_ccdb *db) return ENOMEM; } - /* TODO: read configuration from the config file, adjust quotas */ - ret = sss_sec_init(db, NULL, &secdb->sctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, diff --git a/src/responder/kcm/kcmsrv_ccache_secrets.c b/src/responder/kcm/kcmsrv_ccache_secrets.c index 4c52497d45..7b019fdedc 100644 --- a/src/responder/kcm/kcmsrv_ccache_secrets.c +++ b/src/responder/kcm/kcmsrv_ccache_secrets.c @@ -659,7 +659,9 @@ static errno_t sec_get_ccache_recv(struct tevent_req *req, /* * The actual sssd-secrets back end */ -static errno_t ccdb_sec_init(struct kcm_ccdb *db) +static errno_t ccdb_sec_init(struct kcm_ccdb *db, + struct confdb_ctx *cdb, + const char *confdb_service_path) { struct ccdb_sec *secdb = NULL; From 3f83cc3a2a0ed03242d0c73ed4a9021ed62e0889 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Wed, 28 Nov 2018 21:22:22 +0100 Subject: [PATCH 6/7] KCM: Configurable quotas for the secdb ccache back end Related: https://pagure.io/SSSD/sssd/issue/3386 Exposes three new options for the [kcm] responder to set the global ccache limit, the per-uid ccache limit and the payload size. --- src/confdb/confdb.h | 3 ++ src/config/cfg_rules.ini | 3 ++ src/man/sssd-kcm.8.xml | 37 +++++++++++++++ src/responder/kcm/kcmsrv_ccache_secdb.c | 61 ++++++++++++++++++++++++- 4 files changed, 103 insertions(+), 1 deletion(-) diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index d09d6b4c36..727841659e 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -266,6 +266,9 @@ #define CONFDB_KCM_CONF_ENTRY "config/kcm" #define CONFDB_KCM_SOCKET "socket_path" #define CONFDB_KCM_DB "ccache_storage" /* Undocumented on purpose */ +#define CONFDB_KCM_MAX_CCACHES "max_ccaches" +#define CONFDB_KCM_MAX_UID_CCACHES "max_uid_ccaches" +#define CONFDB_KCM_MAX_CCACHE_SIZE "max_ccache_size" /* Certificate mapping rules */ #define CONFDB_CERTMAP_BASEDN "cn=certmap,cn=config" diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini index 929e6149a7..9a87eb625f 100644 --- a/src/config/cfg_rules.ini +++ b/src/config/cfg_rules.ini @@ -312,6 +312,9 @@ option = description option = socket_path option = ccache_storage option = responder_idle_timeout +option = max_ccaches +option = max_uid_ccaches +option = max_ccache_size # Session recording [rule/allowed_session_recording_options] diff --git a/src/man/sssd-kcm.8.xml b/src/man/sssd-kcm.8.xml index 4e4aaa38ea..2f66e56a4a 100644 --- a/src/man/sssd-kcm.8.xml +++ b/src/man/sssd-kcm.8.xml @@ -201,6 +201,43 @@ systemctl restart sssd-kcm.service </para> </listitem> </varlistentry> + <varlistentry> + <term>max_ccaches (integer)</term> + <listitem> + <para> + How many credential caches does the KCM database allow + for all users. + </para> + <para> + Default: 0 (unlimited, only the per-UID quota is enforced) + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>max_uid_ccaches (integer)</term> + <listitem> + <para> + How many credential caches does the KCM database allow + per UID. This is equivalent to <quote>with how many + principals you can kinit</quote>. + </para> + <para> + Default: 64 + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>max_ccache_size (integer)</term> + <listitem> + <para> + How big can a credential cache be per ccache. Each + service ticket accounts into this quota. + </para> + <para> + Default: 65536 + </para> + </listitem> + </varlistentry> </variablelist> </refsect1> diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c index 5ccb21aa73..26ee1032d7 100644 --- a/src/responder/kcm/kcmsrv_ccache_secdb.c +++ b/src/responder/kcm/kcmsrv_ccache_secdb.c @@ -526,13 +526,72 @@ static errno_t ccdb_secdb_init(struct kcm_ccdb *db, { struct ccdb_secdb *secdb = NULL; errno_t ret; + struct sss_sec_hive_config **kcm_section_quota; + struct sss_sec_quota_opt dfl_kcm_nest_level = { + .opt_name = CONFDB_SEC_CONTAINERS_NEST_LEVEL, + .default_value = DEFAULT_SEC_CONTAINERS_NEST_LEVEL, + }; + struct sss_sec_quota_opt dfl_kcm_max_secrets = { + .opt_name = CONFDB_KCM_MAX_CCACHES, + .default_value = DEFAULT_SEC_KCM_MAX_SECRETS, + }; + struct sss_sec_quota_opt dfl_kcm_max_uid_secrets = { + .opt_name = CONFDB_KCM_MAX_UID_CCACHES, + .default_value = DEFAULT_SEC_KCM_MAX_UID_SECRETS, + }; + struct sss_sec_quota_opt dfl_kcm_max_payload_size = { + .opt_name = CONFDB_KCM_MAX_CCACHE_SIZE, + .default_value = DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE, + }; + secdb = talloc_zero(db, struct ccdb_secdb); if (secdb == NULL) { return ENOMEM; } - ret = sss_sec_init(db, NULL, &secdb->sctx); + kcm_section_quota = talloc_zero_array(secdb, + struct sss_sec_hive_config *, + 2); + if (kcm_section_quota == NULL) { + talloc_free(secdb); + return ENOMEM; + } + + kcm_section_quota[0] = talloc_zero(kcm_section_quota, + struct sss_sec_hive_config); + if (kcm_section_quota == NULL) { + talloc_free(secdb); + return ENOMEM; + } + kcm_section_quota[0]->hive_name = "kcm"; + + ret = sss_sec_get_quota(cdb, + confdb_service_path, + &dfl_kcm_nest_level, + &dfl_kcm_max_secrets, + &dfl_kcm_max_uid_secrets, + &dfl_kcm_max_payload_size, + &kcm_section_quota[0]->quota); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to get KCM global quotas [%d]: %s\n", + ret, sss_strerror(ret)); + talloc_free(secdb); + return ret; + } + + if (kcm_section_quota[0]->quota.max_uid_secrets > 0) { + /* Even cn=default is considered a secret that adds up to + * the quota. To avoid off-by-one-confusion, increase + * the quota by two to 1) account for the cn=default object + * and 2) always allow writing to cn=defaults even if we + * are exactly at the quota limit + */ + kcm_section_quota[0]->quota.max_uid_secrets += 2; + } + + ret = sss_sec_init(db, kcm_section_quota, &secdb->sctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize the security database\n"); From 60d248094a36d2466eccdae5ba70e0e23889a3a2 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Mon, 26 Nov 2018 21:10:21 +0100 Subject: [PATCH 7/7] TESTS: Add tests for the configurable quotas Related: https://pagure.io/SSSD/sssd/issue/3386 --- src/tests/multihost/basic/conftest.py | 8 ++ src/tests/multihost/basic/test_kcm.py | 104 +++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/tests/multihost/basic/conftest.py b/src/tests/multihost/basic/conftest.py index 86431ad25c..83f98af22b 100644 --- a/src/tests/multihost/basic/conftest.py +++ b/src/tests/multihost/basic/conftest.py @@ -399,6 +399,14 @@ def create_posix_usersgroups(session_multihost): assert ret == 'Success' +@pytest.fixture(scope='session') +def create_many_user_principals(session_multihost): + krb = krb5srv(session_multihost.master[0], 'EXAMPLE.TEST') + for i in range(1, 65): + username = "user%04d" % i + krb.add_principal(username, 'user', 'Secret123') + + @pytest.fixture(scope="session", autouse=True) def setup_session(request, session_multihost, package_install, diff --git a/src/tests/multihost/basic/test_kcm.py b/src/tests/multihost/basic/test_kcm.py index 7fdf285e81..79dae8091f 100644 --- a/src/tests/multihost/basic/test_kcm.py +++ b/src/tests/multihost/basic/test_kcm.py @@ -179,7 +179,7 @@ def test_ssh_forward_creds(self, multihost, enable_kcm): def test_kvno_display(self, multihost, enable_kcm): """ - Test kvno correctly displays vesion numbers of principals + @Title: kcm: Test kvno correctly displays vesion numbers of principals #https://pagure.io/SSSD/sssd/issue/3757 """ ssh = SSHClient(multihost.master[0].sys_hostname, @@ -195,3 +195,105 @@ def test_kvno_display(self, multihost, enable_kcm): else: pytest.fail("kvno display was improper") ssh.close() + + def test_kcm_peruid_quota(self, + multihost, + enable_kcm, + create_many_user_principals): + """ + @Title: kcm: Make sure the quota limits a client, but only that client + """ + ssh_foo2 = SSHClient(multihost.master[0].sys_hostname, + username='foo2', password='Secret123') + ssh_foo3 = SSHClient(multihost.master[0].sys_hostname, + username='foo3', password='Secret123') + + # The loop would request 63 users, plus there is foo3 we authenticated + # earlier, so this should exactly deplete the quota, but should succeed + for i in range(1, 64): + username = "user%04d" % i + (_, _, exit_status) = ssh_foo3.execute_cmd('kinit %s' % username, + stdin='Secret123') + assert exit_status == 0 + + # this kinit should be exactly one over the peruid limit + (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064', + stdin='Secret123') + assert exit_status != 0 + + # Since this is a per-uid limit, another user should be able to kinit + # just fine + (_, _, exit_status) = ssh_foo2.execute_cmd('kinit user0064', + stdin='Secret123') + assert exit_status == 0 + + # kdestroy as the original user, the quota should allow a subsequent + # kinit + ssh_foo3.execute_cmd('kdestroy -A') + (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064', + stdin='Secret123') + assert exit_status == 0 + + ssh_foo2.execute_cmd('kdestroy -A') + ssh_foo2.close() + ssh_foo3.execute_cmd('kdestroy -A') + ssh_foo3.close() + + def test_kcm_peruid_quota_increase(self, + multihost, + enable_kcm, + create_many_user_principals): + """ + @Title: kcm: Quota increase + + Increasing the peruid quota allows a client to store more + data + """ + ssh_foo3 = SSHClient(multihost.master[0].sys_hostname, + username='foo3', password='Secret123') + + # The loop would request 63 users, plus there is foo3 we authenticated + # earlier, so this should exactly deplete the quota, but should succeed + for i in range(1, 64): + username = "user%04d" % i + (_, _, exit_status) = ssh_foo3.execute_cmd('kinit %s' % username, + stdin='Secret123') + assert exit_status == 0 + + # this kinit should be exactly one over the peruid limit + (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064', + stdin='Secret123') + assert exit_status != 0 + + set_param(multihost, 'kcm', 'max_uid_ccaches', '65') + self._restart_kcm(multihost) + + # Now the kinit should work as we increased the limit + (_, _, exit_status) = ssh_foo3.execute_cmd('kinit user0064', + stdin='Secret123') + assert exit_status == 0 + + ssh_foo3.execute_cmd('kdestroy -A') + ssh_foo3.close() + + def test_kcm_payload_low_quota(self, + multihost, + enable_kcm): + """ + @Title: kcm: Quota enforcement + + Set a prohibitive quota for the per-ccache payload limit and + make sure it gets enforced + """ + + ssh_foo3 = SSHClient(multihost.master[0].sys_hostname, + username='foo3', password='Secret123') + ssh_foo3.execute_cmd('kdestroy -A') + ssh_foo3.close() + + set_param(multihost, 'kcm', 'max_ccache_size', '1') + self._restart_kcm(multihost) + + with pytest.raises(paramiko.ssh_exception.AuthenticationException): + ssh_foo3 = SSHClient(multihost.master[0].sys_hostname, + username='foo3', password='Secret123')
_______________________________________________ sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org