From 4db56d8c90a6467a216590e5ba3bdcd2a2bf1ae9 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Tue, 30 May 2017 12:51:19 +0200 Subject: [PATCH 88/93] SECRETS: Read the quotas for cn=secrets from [secrets/secrets] configuration subsection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch makes obsoletes the old way of configuring quotas for the secrets responder. Instead, adds a new way of configuring each hive separately in a configuration subsection, e.g. [secrets/secrets] max_secrets = 123 The old way is still supported as a backwards-compatible method. Reviewed-by: Simo Sorce Reviewed-by: Fabiano FidĂȘncio --- src/config/cfg_rules.ini | 10 +++ src/man/sssd-secrets.5.xml | 45 ++++++++++++- src/responder/secrets/secsrv.c | 139 +++++++++++++++++++++++++++++++++-------- src/tests/intg/test_secrets.py | 125 +++++++++++++++++++++++++++--------- 4 files changed, 262 insertions(+), 57 deletions(-) diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini index ae60c73c871e1ac18a26124232e1f9f7c9f8fabb..a963eb49c9010924bda6a48c47d80c868ffd6ddd 100644 --- a/src/config/cfg_rules.ini +++ b/src/config/cfg_rules.ini @@ -12,6 +12,7 @@ section = secrets section = kcm section = session_recording section_re = ^secrets/users/[0-9]\+$ +section_re = ^secrets/secrets$ section_re = ^domain/[^/\@]\+$ section_re = ^domain/[^/\@]\+/[^/\@]\+$ section_re = ^application/[^/\@]\+$ @@ -256,6 +257,15 @@ option = max_secrets option = max_payload_size option = responder_idle_timeout +[rule/allowed_sec_hive_options] +validator = ini_allowed_options +section_re = ^secrets/secrets$ + +# Secrets service - per-hive configuration +option = containers_nest_level +option = max_secrets +option = max_payload_size + [rule/allowed_sec_users_options] validator = ini_allowed_options section_re = ^secrets/users/[0-9]\+$ diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml index 44a86c3fb56a8bdebebd01e9f49ad171986282a4..d50cb13d8a0dcbdb7919c1e38d6d5976dcc2abf1 100644 --- a/src/man/sssd-secrets.5.xml +++ b/src/man/sssd-secrets.5.xml @@ -57,6 +57,32 @@ collide between users. Secrets can be stored inside containers which can be nested. + + Since the secrets responder can be used both externally to store + general secrets, as described in the rest of this man page, but + also internally by other SSSD components to store their secret + material, some configuration options, like quotas can be configured + per hive in a configuration subsection named after + the hive. The currently supported hives are: + + + secrets + secrets for general usage + + + kcm + + used by the + + sssd-kcm + 8 + + service. + + + + + @@ -144,6 +170,12 @@ systemctl enable sssd-secrets.service + + + The following options affect only the secrets hive + and therefore should be set in a per-hive subsection. + + containers_nest_level (integer) @@ -161,7 +193,7 @@ systemctl enable sssd-secrets.service This option specifies the maximum number of secrets that - can be stored. + can be stored in the hive. Default: 1024 @@ -181,6 +213,17 @@ systemctl enable sssd-secrets.service + + For example, to adjust quotas differently for both the secrets + and the kcm hives, configure the following: + +[secrets/secrets] +max_payload_size = 128 + +[secrets/kcm] +max_payload_size = 256 + + The following options are only applicable for configurations that use the proxy provider. diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c index e3a8c1476af8d9c2c8b87a11ca930e12f381ef94..db12cbbc3eb9317b6d449a5d2b2d370afebf247e 100644 --- a/src/responder/secrets/secsrv.c +++ b/src/responder/secrets/secsrv.c @@ -33,6 +33,100 @@ #define DEFAULT_SEC_MAX_SECRETS 1024 #define DEFAULT_SEC_MAX_PAYLOAD_SIZE 16 +static int sec_get_quota(struct sec_ctx *sctx, + const char *section_config_path, + int default_max_containers_nest_level, + int default_max_num_secrets, + int default_max_payload, + struct sec_quota *quota) +{ + int ret; + + ret = confdb_get_int(sctx->rctx->cdb, + section_config_path, + CONFDB_SEC_CONTAINERS_NEST_LEVEL, + default_max_containers_nest_level, + "a->containers_nest_level); + + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to get container nesting level for %s\n", + section_config_path); + return ret; + } + + ret = confdb_get_int(sctx->rctx->cdb, + section_config_path, + CONFDB_SEC_MAX_SECRETS, + default_max_num_secrets, + "a->max_secrets); + + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to get maximum number of entries for %s\n", + section_config_path); + return ret; + } + + ret = confdb_get_int(sctx->rctx->cdb, + section_config_path, + CONFDB_SEC_MAX_PAYLOAD_SIZE, + default_max_payload, + "a->max_payload_size); + + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Failed to get payload's maximum size for an entry in %s\n", + section_config_path); + return ret; + } + + return EOK; +} + +static int sec_get_hive_config(struct sec_ctx *sctx, + const char *hive_name, + struct sec_hive_config *hive_config, + int default_max_containers_nest_level, + int default_max_num_secrets, + int default_max_payload) +{ + int ret; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(sctx); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + hive_config->confdb_section = talloc_asprintf(sctx, + "config/secrets/%s", + hive_name); + if (hive_config->confdb_section == NULL) { + ret = ENOMEM; + goto done; + } + + ret = sec_get_quota(sctx, + hive_config->confdb_section, + default_max_containers_nest_level, + default_max_num_secrets, + default_max_payload, + &hive_config->quota); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot read quota settings for %s [%d]: %s\n", + hive_name, ret, sss_strerror(ret)); + goto done; + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + static int sec_get_config(struct sec_ctx *sctx) { int ret; @@ -48,39 +142,32 @@ static int sec_get_config(struct sec_ctx *sctx) goto fail; } - ret = confdb_get_int(sctx->rctx->cdb, - sctx->rctx->confdb_service_path, - CONFDB_SEC_CONTAINERS_NEST_LEVEL, - DEFAULT_SEC_CONTAINERS_NEST_LEVEL, - &sctx->sec_config.quota.containers_nest_level); - - if (ret != EOK) { - DEBUG(SSSDBG_FATAL_FAILURE, - "Failed to get containers' maximum depth\n"); - goto fail; - } - - ret = confdb_get_int(sctx->rctx->cdb, - sctx->rctx->confdb_service_path, - CONFDB_SEC_MAX_SECRETS, - DEFAULT_SEC_MAX_SECRETS, - &sctx->sec_config.quota.max_secrets); - + /* 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 = sec_get_quota(sctx, + sctx->rctx->confdb_service_path, + DEFAULT_SEC_CONTAINERS_NEST_LEVEL, + DEFAULT_SEC_MAX_SECRETS, + DEFAULT_SEC_MAX_PAYLOAD_SIZE, + &sctx->sec_config.quota); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, - "Failed to get maximum number of entries\n"); + "Failed to get legacy global quotas\n"); goto fail; } - ret = confdb_get_int(sctx->rctx->cdb, - sctx->rctx->confdb_service_path, - CONFDB_SEC_MAX_PAYLOAD_SIZE, - DEFAULT_SEC_MAX_PAYLOAD_SIZE, - &sctx->sec_config.quota.max_payload_size); - + /* Read the per-hive configuration */ + ret = sec_get_hive_config(sctx, + "secrets", + &sctx->sec_config, + sctx->sec_config.quota.containers_nest_level, + sctx->sec_config.quota.max_secrets, + sctx->sec_config.quota.max_payload_size); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, - "Failed to get payload's maximum size for an entry\n"); + "Failed to get configuration of the secrets hive\n"); goto fail; } diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py index 32ea58ff017f01bc6a28f826d10dabff60761bcb..bb94ffb47666f964fae2764444f7d28f3b311145 100644 --- a/src/tests/intg/test_secrets.py +++ b/src/tests/intg/test_secrets.py @@ -169,36 +169,6 @@ def test_crd_ops(setup_for_secrets, secrets_cli): cli.del_secret("foo") assert str(err404.value).startswith("404") - # Don't allow storing more secrets after reaching the max - # number of entries. - MAX_SECRETS = 10 - - sec_value = "value" - for x in range(MAX_SECRETS): - cli.set_secret(str(x), sec_value) - - with pytest.raises(HTTPError) as err507: - cli.set_secret(str(MAX_SECRETS), sec_value) - assert str(err507.value).startswith("507") - - # Delete all stored secrets used for max secrets tests - for x in range(MAX_SECRETS): - cli.del_secret(str(x)) - - # Don't allow storing a secrets which has a payload larger - # than max_payload_size - KILOBYTE = 1024 - MAX_PAYLOAD_SIZE = 2 * KILOBYTE - - sec_value = "x" * MAX_PAYLOAD_SIZE - - cli.set_secret("foo", sec_value) - - sec_value += "x" - with pytest.raises(HTTPError) as err413: - cli.set_secret("bar", sec_value) - assert str(err413.value).startswith("413") - def run_curlwrap_tool(args, exp_http_code): cmd = subprocess.Popen(args, @@ -434,3 +404,98 @@ def test_idle_timeout(setup_for_cli_timeout_test): nfds_post = get_num_fds(secpid) assert nfds_pre == nfds_post + + +def run_quota_test(cli, max_secrets, max_payload_size): + sec_value = "value" + for x in range(max_secrets): + cli.set_secret(str(x), sec_value) + + with pytest.raises(HTTPError) as err507: + cli.set_secret(str(max_secrets), sec_value) + assert str(err507.value).startswith("507") + + # Delete all stored secrets used for max secrets tests + for x in range(max_secrets): + cli.del_secret(str(x)) + + # Don't allow storing a secrets which has a payload larger + # than max_payload_size + KILOBYTE = 1024 + kb_payload_size = max_payload_size * KILOBYTE + + sec_value = "x" * kb_payload_size + + cli.set_secret("foo", sec_value) + + sec_value += "x" + with pytest.raises(HTTPError) as err413: + cli.set_secret("bar", sec_value) + assert str(err413.value).startswith("413") + + +@pytest.fixture +def setup_for_global_quota(request): + conf = unindent("""\ + [sssd] + domains = local + services = nss + + [domain/local] + id_provider = local + + [secrets] + max_secrets = 10 + max_payload_size = 2 + """).format(**locals()) + + create_conf_fixture(request, conf) + create_sssd_secrets_fixture(request) + return None + + +def test_global_quota(setup_for_global_quota, secrets_cli): + """ + Test that the deprecated configuration of quotas in the global + secrets section is still supported + """ + cli = secrets_cli + + # Don't allow storing more secrets after reaching the max + # number of entries. + run_quota_test(cli, 10, 2) + + +@pytest.fixture +def setup_for_secrets_quota(request): + conf = unindent("""\ + [sssd] + domains = local + services = nss + + [domain/local] + id_provider = local + + [secrets] + max_secrets = 5 + max_payload_size = 1 + + [secrets/secrets] + max_secrets = 10 + max_payload_size = 2 + """).format(**locals()) + + create_conf_fixture(request, conf) + create_sssd_secrets_fixture(request) + return None + + +def test_sec_quota(setup_for_secrets_quota, secrets_cli): + """ + Test that the new secrets/secrets section takes precedence. + """ + cli = secrets_cli + + # Don't allow storing more secrets after reaching the max + # number of entries. + run_quota_test(cli, 10, 2) -- 2.14.1