Skip to content

Commit

Permalink
feat: add validity length (in days) for certs (#981)
Browse files Browse the repository at this point in the history
* feat: add validity length (in days) for certs

* chore(jans-pycloudlib): updated build (#982)

Signed-off-by: mo-auto <54212639+mo-auto@users.noreply.github.com>

Co-authored-by: mo-auto <54212639+mo-auto@users.noreply.github.com>
  • Loading branch information
iromli and mo-auto authored Mar 7, 2022
1 parent 3be0ffa commit abc89dc
Show file tree
Hide file tree
Showing 16 changed files with 145 additions and 34 deletions.
2 changes: 1 addition & 1 deletion docker-jans-auth-server/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pinned to py3-grpcio version to avoid failure on native extension build
grpcio==1.41.0
libcst<0.4
git+https://github.com/JanssenProject/jans@5618dd60a340e46377afc20fdc9f9d39248cb1ed#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@2e14ca7dfe600bf1136b4435749a600166328c9f#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
4 changes: 2 additions & 2 deletions docker-jans-certmanager/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM bellsoft/liberica-openjre-alpine:11
FROM bellsoft/liberica-openjre-alpine:11.0.13-8

# ===============
# Alpine packages
Expand All @@ -17,7 +17,7 @@ RUN apk update \

# JAR files required to generate OpenID Connect keys
ENV CN_VERSION=1.0.0-SNAPSHOT
ENV CN_BUILD_DATE='2022-01-25 09:43'
ENV CN_BUILD_DATE='2022-03-06 08:13'
ENV CN_SOURCE_URL=https://jenkins.jans.io/maven/io/jans/jans-auth-client/${CN_VERSION}/jans-auth-client-${CN_VERSION}-jar-with-dependencies.jar

RUN wget -q ${CN_SOURCE_URL} -P /app/javalibs/
Expand Down
4 changes: 3 additions & 1 deletion docker-jans-certmanager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Supported services:
Options:

- `source`: `from-files` or empty string
- `valid-to`: Validity length in days (default to `365`)

1. `auth`

Expand Down Expand Up @@ -138,6 +139,7 @@ Supported services:
Options:

- `subj-alt-name`: Subject Alternative Name (SAN) for certificate (default to `localhost`)
- `valid-to`: Validity length in days (default to `365`)

1. `client-api`

Expand All @@ -154,6 +156,7 @@ Supported services:

- `application-cn`: Subject alternative name for application certificate (default to `localhost`)
- `admin-cn`: Subject alternative name for admin certificate (default to `localhost`)
- `valid-to`: Validity length in days (default to `365`)

#### prune

Expand Down Expand Up @@ -240,4 +243,3 @@ spec:
args: ["patch", "auth", "--opts", "interval:48"]
restartPolicy: Never
```
2 changes: 1 addition & 1 deletion docker-jans-certmanager/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
grpcio==1.41.0
click==6.7
libcst<0.4
git+https://github.com/JanssenProject/jans@5618dd60a340e46377afc20fdc9f9d39248cb1ed#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@2e14ca7dfe600bf1136b4435749a600166328c9f#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
5 changes: 3 additions & 2 deletions docker-jans-certmanager/scripts/base_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
logger = logging.getLogger("certmanager")


class BaseHandler(object):
class BaseHandler:
def __init__(self, manager, dry_run, **opts):
self.manager = manager
self.dry_run = dry_run
Expand All @@ -21,7 +21,7 @@ def _patch_keystore(self, prefix, hostname, passwd):
generate_keystore(prefix, hostname, passwd)
return keystore_fn

def _patch_cert_key(self, prefix, extra_dns=None):
def _patch_cert_key(self, prefix, extra_dns=None, valid_to=365):
cert_fn = f"/etc/certs/{prefix}.crt"
key_fn = f"/etc/certs/{prefix}.key"

Expand All @@ -35,6 +35,7 @@ def _patch_cert_key(self, prefix, extra_dns=None):
self.manager.config.get("state"),
self.manager.config.get("city"),
extra_dns=extra_dns,
valid_to=valid_to,
)
return cert_fn, key_fn

Expand Down
9 changes: 9 additions & 0 deletions docker-jans-certmanager/scripts/client_api_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,18 @@

class ClientApiHandler(BaseHandler):
def generate_x509(self, suffix, cert_cn):
try:
valid_to = int(self.opts.get("valid-to", 365))
except ValueError:
valid_to = 365
finally:
if valid_to < 1:
valid_to = 365

cert_file, key_file = self._patch_cert_key(
suffix,
extra_dns=[cert_cn],
valid_to=valid_to,
)
return cert_file, key_file

Expand Down
10 changes: 9 additions & 1 deletion docker-jans-certmanager/scripts/ldap_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@ def generate_x509(self):
alt_name = self.opts.get("subj-alt-name", "localhost")
suffix = "opendj"

self._patch_cert_key(suffix, extra_dns=[alt_name])
try:
valid_to = int(self.opts.get("valid-to", 365))
except ValueError:
valid_to = 365
finally:
if valid_to < 1:
valid_to = 365

self._patch_cert_key(suffix, extra_dns=[alt_name], valid_to=valid_to)

with open("/etc/certs/{}.pem".format(suffix), "w") as fw:
with open("/etc/certs/{}.crt".format(suffix)) as fr:
Expand Down
10 changes: 10 additions & 0 deletions docker-jans-certmanager/scripts/web_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ class WebHandler(BaseHandler):
def patch(self):
source = self.opts.get("source", "")

try:
valid_to = int(self.opts.get("valid-to", 365))
except ValueError:
valid_to = 365
finally:
if valid_to < 1:
valid_to = 365

ssl_cert = "/etc/certs/web_https.crt"
ssl_key = "/etc/certs/web_https.key"
ssl_csr = "/etc/certs/web_https.csr"
Expand Down Expand Up @@ -45,6 +53,7 @@ def patch(self):
country_code,
state,
city,
valid_to=valid_to,
)

logger.info(f"Creating self-generated {ssl_csr}, {ssl_cert}, and {ssl_key}")
Expand All @@ -58,6 +67,7 @@ def patch(self):
country_code,
state,
city,
valid_to=valid_to,
)

if not self.dry_run:
Expand Down
2 changes: 1 addition & 1 deletion docker-jans-client-api/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
grpcio==1.41.0
ruamel.yaml==0.16.10
libcst<0.4
git+https://github.com/JanssenProject/jans@5618dd60a340e46377afc20fdc9f9d39248cb1ed#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@2e14ca7dfe600bf1136b4435749a600166328c9f#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
2 changes: 1 addition & 1 deletion docker-jans-config-api/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pinned to py3-grpcio version to avoid failure on native extension build
grpcio==1.41.0
libcst<0.4
git+https://github.com/JanssenProject/jans@5618dd60a340e46377afc20fdc9f9d39248cb1ed#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@2e14ca7dfe600bf1136b4435749a600166328c9f#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
2 changes: 1 addition & 1 deletion docker-jans-configurator/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ click==6.7
marshmallow==3.10.0
fqdn==1.4.0
libcst<0.4
git+https://github.com/JanssenProject/jans@5618dd60a340e46377afc20fdc9f9d39248cb1ed#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@2e14ca7dfe600bf1136b4435749a600166328c9f#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
2 changes: 1 addition & 1 deletion docker-jans-fido2/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pinned to py3-grpcio version to avoid failure on native extension build
grpcio==1.41.0
libcst<0.4
git+https://github.com/JanssenProject/jans@5618dd60a340e46377afc20fdc9f9d39248cb1ed#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@2e14ca7dfe600bf1136b4435749a600166328c9f#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
2 changes: 1 addition & 1 deletion docker-jans-persistence-loader/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
grpcio==1.41.0
ldif==4.1.1
libcst<0.4
git+https://github.com/JanssenProject/jans@5618dd60a340e46377afc20fdc9f9d39248cb1ed#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@2e14ca7dfe600bf1136b4435749a600166328c9f#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
2 changes: 1 addition & 1 deletion docker-jans-scim/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pinned to py3-grpcio version to avoid failure on native extension build
grpcio==1.41.0
libcst<0.4
git+https://github.com/JanssenProject/jans@5618dd60a340e46377afc20fdc9f9d39248cb1ed#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@2e14ca7dfe600bf1136b4435749a600166328c9f#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
23 changes: 12 additions & 11 deletions jans-pycloudlib/jans/pycloudlib/pki.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,19 @@ def generate_public_key(filename, private_key, is_ca=False, add_san=False, add_k
Keyword arguments:
- ``email``: Email address for subject/issuer.
- ``hostname``: Hostname (common name) for subject/issuer.
- ``org_name``: Organization name for subject/issuer.
- ``country_code``: Country name in ISO format for subject/issuer.
- ``state``: State/province name for subject/issuer.
- ``city``: City/locality name for subject/issuer.
- ``extra_dns``: Additional DNS names (added if ``add_san`` argument is set to ``True``).
- ``extra_ips``: Additional IP addresses (added if ``add_san`` argument is set to ``True``).
- ``email``: Email address for subject/issuer.
- ``hostname``: Hostname (common name) for subject/issuer.
- ``org_name``: Organization name for subject/issuer.
- ``country_code``: Country name in ISO format for subject/issuer.
- ``state``: State/province name for subject/issuer.
- ``city``: City/locality name for subject/issuer.
- ``extra_dns``: Additional DNS names (added if ``add_san`` argument is set to ``True``).
- ``extra_ips``: Additional IP addresses (added if ``add_san`` argument is set to ``True``).
- ``valid_to``: Validity length in days.
"""

valid_from = datetime.utcnow()
valid_to = valid_from + timedelta(days=365)
valid_to = valid_from + timedelta(days=kwargs.get("valid_to", 365))

# issuer equals subject because we use self-signed
subject = issuer = x509.Name([
Expand Down Expand Up @@ -229,7 +230,7 @@ def generate_csr(filename, private_key, add_san=False, add_key_usage=False, **kw
return csr


def sign_csr(filename, csr, ca_private_key, ca_public_key):
def sign_csr(filename, csr, ca_private_key, ca_public_key, **kwargs):
"""Sign a certificate signing request (CSR).
:param filename: Path to signed certificate.
Expand All @@ -239,7 +240,7 @@ def sign_csr(filename, csr, ca_private_key, ca_public_key):
"""

valid_from = datetime.utcnow()
valid_to = valid_from + timedelta(days=365)
valid_to = valid_from + timedelta(days=kwargs.get("valid_to", 365))

builder = (
x509.CertificateBuilder()
Expand Down
98 changes: 89 additions & 9 deletions jans-pycloudlib/jans/pycloudlib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,35 @@ def decode_text(text: AnyStr, key: AnyStr) -> bytes:
return unpadder.update(padded_data) + unpadder.finalize()


def generate_ssl_certkey(suffix, email, hostname, org_name, country_code,
state, city, base_dir="/etc/certs",
extra_dns=None, extra_ips=None):
def generate_ssl_certkey(
suffix,
email,
hostname,
org_name,
country_code,
state,
city,
base_dir="/etc/certs",
extra_dns=None,
extra_ips=None,
valid_to=365,
):
"""Generate SSL public and private keys.
:param suffix: Suffix as basename (i.e. ``auth-server``)
:param email: Email address for subject/issuer.
:param hostname: Hostname (common name) for subject/issuer.
:param org_name: Organization name for subject/issuer.
:param country_code: Country name in ISO format for subject/issuer.
:param state: State/province name for subject/issuer.
:param city: City/locality name for subject/issuer.
:param base_dir: Directory to store generated public and private keys.
:param extra_dns: Additional DNS names.
:param extra_ips: Additional IP addresses.
:param valid_to: Validity length in days.
:returns: A pair of path to generated public and private keys.
"""

key_fn = f"{base_dir}/{suffix}.key"
priv_key = generate_private_key(key_fn)

Expand All @@ -313,6 +339,7 @@ def generate_ssl_certkey(suffix, email, hostname, org_name, country_code,
org_name=org_name,
extra_dns=extra_dns,
extra_ips=extra_ips,
valid_to=valid_to,
)
return cert_fn, key_fn

Expand Down Expand Up @@ -380,8 +407,30 @@ def generate_keystore(suffix, hostname, keypasswd, jks_fn="", in_key="", in_cert
raise RuntimeError(f"Failed to generate JKS keystore {jks_fn}; reason={err.decode()}")


def generate_ssl_ca_certkey(suffix, email, hostname, org_name, country_code,
state, city, base_dir="/etc/certs"):
def generate_ssl_ca_certkey(
suffix,
email,
hostname,
org_name,
country_code,
state,
city,
base_dir="/etc/certs",
valid_to=365,
):
"""Generate SSL public and private keys for CA.
:param suffix: Suffix as basename (i.e. ``auth-server``)
:param email: Email address for subject/issuer.
:param hostname: Hostname (common name) for subject/issuer.
:param org_name: Organization name for subject/issuer.
:param country_code: Country name in ISO format for subject/issuer.
:param state: State/province name for subject/issuer.
:param city: City/locality name for subject/issuer.
:param base_dir: Directory to store generated public and private keys.
:param valid_to: Validity length in days.
:returns: A pair of path to generated public and private keys.
"""

key_fn = f"{base_dir}/{suffix}.key"
priv_key = generate_private_key(key_fn)
Expand All @@ -397,13 +446,44 @@ def generate_ssl_ca_certkey(suffix, email, hostname, org_name, country_code,
city=city,
email=email,
org_name=org_name,
valid_to=valid_to,
)
return cert_fn, key_fn


def generate_signed_ssl_certkey(suffix, ca_key_fn, ca_cert_fn, email, hostname, org_name,
country_code, state, city, base_dir="/etc/certs",
extra_dns=None, extra_ips=None):
def generate_signed_ssl_certkey(
suffix,
ca_key_fn,
ca_cert_fn,
email,
hostname,
org_name,
country_code,
state,
city,
base_dir="/etc/certs",
extra_dns=None,
extra_ips=None,
valid_to=365,
):
"""Generate SSL public and private keys signed by CA.
:param suffix: Suffix as basename (i.e. ``auth-server``)
:param ca_key_fn: Path to CA private key.
:param ca_cert_fn: Path to CA public key.
:param email: Email address for subject/issuer.
:param hostname: Hostname (common name) for subject/issuer.
:param org_name: Organization name for subject/issuer.
:param country_code: Country name in ISO format for subject/issuer.
:param state: State/province name for subject/issuer.
:param city: City/locality name for subject/issuer.
:param base_dir: Directory to store generated public and private keys.
:param extra_dns: Additional DNS names.
:param extra_ips: Additional IP addresses.
:param valid_to: Validity length in days.
:returns: A pair of path to generated public and private keys.
"""

key_fn = f"{base_dir}/{suffix}.key"
priv_key = generate_private_key(key_fn)

Expand Down Expand Up @@ -435,5 +515,5 @@ def generate_signed_ssl_certkey(suffix, ca_key_fn, ca_cert_fn, email, hostname,
with open(ca_cert_fn, "rb") as f:
ca_cert = x509.load_pem_x509_certificate(f.read())

sign_csr(cert_fn, csr, ca_key, ca_cert)
sign_csr(cert_fn, csr, ca_key, ca_cert, valid_to=valid_to)
return cert_fn, key_fn

0 comments on commit abc89dc

Please sign in to comment.