Skip to content

Commit

Permalink
fix(docker-jans): resolve required keys_ops_type for generating/rotat…
Browse files Browse the repository at this point in the history
…ing keys (#3990)

* fix(docker-jans-configurator): set key_ops_type to all

* fix(docker-jans-certmanager): patch and prune keys with connect/ssa type
  • Loading branch information
iromli committed Feb 27, 2023
1 parent 768fd04 commit 0ed67fb
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 12 deletions.
54 changes: 44 additions & 10 deletions docker-jans-certmanager/scripts/auth_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def encode_jks(manager, jks="/etc/certs/auth-keys.jks"):
return encoded_jks


def generate_openid_keys(passwd, jks_path, dn, exp=48, sig_keys=SIG_KEYS, enc_keys=ENC_KEYS):
def generate_openid_keys(passwd, jks_path, dn, exp=48, sig_keys=SIG_KEYS, enc_keys=ENC_KEYS, key_ops_type="connect"):
if os.path.isfile(jks_path):
os.unlink(jks_path)

Expand All @@ -62,7 +62,7 @@ def generate_openid_keys(passwd, jks_path, dn, exp=48, sig_keys=SIG_KEYS, enc_ke
f"-enc_keys {enc_keys} -sig_keys {sig_keys} "
f"-dnname '{dn}' -expiration_hours {exp} "
f"-keystore {jks_path} -keypasswd {passwd} "
"-key_ops_type connect"
f"-key_ops_type {key_ops_type}"
)
return exec_cmd(cmd)

Expand Down Expand Up @@ -228,8 +228,22 @@ def get_merged_keys(self, exp_hours):
jks_fn = "/etc/certs/auth-keys.jks"
jwks_fn = "/etc/certs/auth-keys.json"
logger.info(f"Generating new {jwks_fn} and {jks_fn}")

# a counter to determine value of `key_ops_type` to be passed to `KeyGenerator`
ops_type_cnt = Counter(key_ops_from_jwk(jwk) for jwk in old_jwks)

# if we have ssa key, use `connect` keys
if ops_type_cnt["ssa"]:
logger.info("Found existing SSA keys ... generating keys with key_ops_type=connect")
key_ops_type = "connect"
else:
# likely upgrading from previous version where SSA keys are not generated initially
logger.info("No existing SSA keys ... generating keys with key_ops_type=all")
key_ops_type = "all"

# if ssa keys exist, use `key_ops_type=connect` otherwise use `key_ops_type=all`
out, err, retcode = generate_openid_keys(
jks_pass, jks_fn, jks_dn, exp=exp_hours, sig_keys=self.sig_keys, enc_keys=self.enc_keys,
jks_pass, jks_fn, jks_dn, exp=exp_hours, sig_keys=self.sig_keys, enc_keys=self.enc_keys, key_ops_type=key_ops_type,
)

if retcode != 0:
Expand All @@ -243,20 +257,28 @@ def get_merged_keys(self, exp_hours):
# won't be added to new JWKS
old_jwks = sorted(old_jwks, key=lambda k: k["exp"], reverse=True)

cnt = Counter(j["alg"] for j in new_jwks)
# counter for `connect` keys
cnt = Counter(
jwk["alg"] for jwk in new_jwks
if key_ops_from_jwk(jwk) == "connect"
)

for jwk in old_jwks:
# exclude alg if it's not allowed
if jwk["alg"] not in self.allowed_key_algs:
continue

# cannot have more than 2 keys for same algorithm in new JWKS
if cnt[jwk["alg"]] > 1:
ops_type = key_ops_from_jwk(jwk)

# cannot have more than 2 connect keys for same algorithm in new JWKS
if ops_type == "connect" and cnt[jwk["alg"]] > 1:
continue

# insert old key to new keys
new_jwks.appendleft(jwk)
cnt[jwk["alg"]] += 1

if ops_type == "connect":
cnt[jwk["alg"]] += 1

# import key to new JKS
keytool_import_key(old_jks_fn, jks_fn, jwk["kid"], jks_pass)
Expand Down Expand Up @@ -504,22 +526,29 @@ def prune(self):
old_jwks = web_keys.get("keys", [])
old_jwks = sorted(old_jwks, key=lambda k: k["exp"], reverse=True)

cnt = Counter(j["alg"] for j in new_jwks)
cnt = Counter(
jwk["alg"] for jwk in new_jwks
if key_ops_from_jwk(jwk) == "connect"
)

for jwk in old_jwks:
# exclude alg if it's not allowed
if jwk["alg"] not in self.allowed_key_algs:
keytool_delete_key(jks_fn, jwk["kid"], jks_pass)
continue

ops_type = key_ops_from_jwk(jwk)

# cannot have more than 1 key for same algorithm in new JWKS
if cnt[jwk["alg"]]:
if ops_type == "connect" and cnt[jwk["alg"]]:
keytool_delete_key(jks_fn, jwk["kid"], jks_pass)
continue

# preserve the key
new_jwks.append(jwk)
cnt[jwk["alg"]] += 1

if ops_type == "connect":
cnt[jwk["alg"]] += 1

web_keys["keys"] = new_jwks

Expand Down Expand Up @@ -640,3 +669,8 @@ def resolve_enc_keys(keys: str) -> str:
enc_keys = default_enc_keys
logger.warning(f"Encryption keys are empty; fallback to default {ENC_KEYS}")
return " ".join(enc_keys)


def key_ops_from_jwk(jwk):
"""Resolve key_ops_type first value."""
return (jwk.get("key_ops_type") or ["connect"])[0]
4 changes: 2 additions & 2 deletions docker-jans-configurator/scripts/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def generate_openid_keys(passwd, jks_path, jwks_path, dn, exp=365, sig_keys=DEFA
"-expiration", "{}".format(exp),
"-keystore", jks_path,
"-keypasswd", passwd,
"-key_ops_type", "connect",
"-key_ops_type", "all",
])
out, err, retcode = exec_cmd(cmd)
if retcode == 0:
Expand All @@ -84,7 +84,7 @@ def generate_openid_keys_hourly(passwd, jks_path, jwks_path, dn, exp=48, sig_key
"-expiration_hours", "{}".format(exp),
"-keystore", jks_path,
"-keypasswd", passwd,
"-key_ops_type", "connect",
"-key_ops_type", "all",
])
out, err, retcode = exec_cmd(cmd)
if retcode == 0:
Expand Down

0 comments on commit 0ed67fb

Please sign in to comment.