def test_get_secret_fingerprint(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] assert SecretUtils.get_secret_fingerprint(a) == "AA:BB" assert SecretUtils.get_secret_fingerprint(b) == "AA:CC" assert SecretUtils.get_secret_fingerprint(c) == "AA:DD" assert SecretUtils.get_secret_fingerprint(d) is None
def test_get_secret_name(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] assert SecretUtils.get_secret_name(a) == "cert" assert SecretUtils.get_secret_name(b) == "chain" assert SecretUtils.get_secret_name(c) == "chain" assert SecretUtils.get_secret_name(d) is None
def test_get_secret_domain(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] assert SecretUtils.get_secret_version(a) == "0" assert SecretUtils.get_secret_version(b) == "1" assert SecretUtils.get_secret_version(c) == "2" assert SecretUtils.get_secret_version(d) is None
def test_get_secret_managed(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] assert SecretUtils.get_secret_managed(a) is False assert SecretUtils.get_secret_managed(b) is True assert SecretUtils.get_secret_managed(c) is True assert SecretUtils.get_secret_managed(d) is False
def test_get_secret_domain(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] assert SecretUtils.get_secret_domain(a) == "1.example.com" assert SecretUtils.get_secret_domain(b) == "2.example.com" assert SecretUtils.get_secret_domain(c) == "2.example.com" assert SecretUtils.get_secret_domain(d) is None
def get_secrets(self, domain, name, reverse=False): # type: (str, str) -> List[Secret] """Get all secrets of a specific type for a domain. The resulting list of secrets is sorted based on secret versions from lowest to highest. :param str domain: Secret domain. :param str name: Secret name. :param bool reverse: Sort the Secrets in reverse order. :return: A list of secrets. :rtype: List[Secret] """ f = {} f[SecretUtils.L_MANAGED] = lambda x: x == "true" f[SecretUtils.L_DOMAIN] = lambda x: x == domain f[SecretUtils.L_NAME] = lambda x: x == name f[SecretUtils.L_VERSION] = lambda x: x is not None f[SecretUtils.L_FINGERPRINT] = lambda x: x is not None s = self.docker_client.secrets.list() s = SecretUtils.filter_secrets(s, f) s = SecretUtils.sort_secrets( s, SecretUtils.L_VERSION, reverse ) return s
def test_get_x509_fingerprint(self): fingerprint = ("D7:5C:60:9E:BE:8F:78:67:1D:0E:16:98:80:96:3A:B5:" "FF:88:A7:94:19:75:6D:11:A0:3E:1F:33:21:90:54:7F") assert SecretUtils.get_x509_fingerprint( os.path.join(ASSET_PATH, "cert.pem") ) == fingerprint
def test_sort_secrets_different_default(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] res = SecretUtils.sort_secrets( [a, b, c, d], SecretUtils.L_VERSION, reverse=True, default="100" ) assert res == [a, b, c, d] res = SecretUtils.sort_secrets( [a, b, c, d], SecretUtils.L_VERSION, reverse=True, default="-1" ) assert res == [d, a, b, c]
def get_all_names(self): # type: () -> List[str] """Get all domain names that have at least one existing secret. :rtype: Set[str] """ f = {} f[SecretUtils.L_MANAGED] = lambda x: x == "true" f[SecretUtils.L_DOMAIN] = lambda x: x is not None f[SecretUtils.L_NAME] = lambda x: x is not None f[SecretUtils.L_VERSION] = lambda x: x is not None f[SecretUtils.L_FINGERPRINT] = lambda x: x is not None s = self.docker_client.secrets.list() s = SecretUtils.filter_secrets(s, f) return {SecretUtils.get_secret_domain(x) for x in s}
def test_sort_secrets(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] res = SecretUtils.sort_secrets( [a, b, c], SecretUtils.L_VERSION, reverse=False, default=None ) assert res == [a, b, c]
def test_sort_secrets_reverse(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] # Case 1 res = SecretUtils.sort_secrets( [a, b, c], SecretUtils.L_VERSION, reverse=True, default=None ) assert res == [c, b, a]
def test_filter_secrets(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] f = {} filtered = SecretUtils.filter_secrets([a, b, c, d], f) assert filtered == [] f[SecretUtils.L_MANAGED] = lambda x: x == "true" f[SecretUtils.L_DOMAIN] = lambda x: x == "2.example.com" filtered = SecretUtils.filter_secrets([a, b, c, d], f) assert filtered == [b, c] f[SecretUtils.L_MANAGED] = lambda x: x == "false" f[SecretUtils.L_DOMAIN] = lambda x: x == "1.example.com" f[SecretUtils.L_NAME] = lambda x: x == "cert" filtered = SecretUtils.filter_secrets([a, b, c, d], f) assert filtered == [a] f[SecretUtils.L_NAME] = lambda x: x == "fullchain" filtered = SecretUtils.filter_secrets([a, b, c, d], f) assert filtered == []
def deploy_cert( # pylint: disable=too-many-arguments self, domain, cert_path, key_path, chain_path, fullchain_path ): # type: (str, str, str, str, str) -> None """Create Docker Swarm Secrets from certificates. :param str domain: Certificate domain. :param str cert_path: Path to the certificate file. :param str key_path: Path to the private key file. :param str chain_path: Path to the certificate chain file. :param str fullchain_path: Path to the fullchain file. """ fp = SecretUtils.get_x509_fingerprint(cert_path) cert = None key = None chain = None fc = None # Create new secrets. if not self.is_secret_deployed(domain, "cert", fp): cert = self.secret_from_file(domain, "cert", cert_path, fp) if not self.is_secret_deployed(domain, "key", fp): key = self.secret_from_file(domain, "key", key_path, fp) if not self.is_secret_deployed(domain, "chain", fp): chain = self.secret_from_file(domain, "chain", chain_path, fp) if not self.is_secret_deployed(domain, "fullchain", fp): fc = self.secret_from_file(domain, "fullchain", fullchain_path, fp) if not cert or not key or not chain or not fc: logger.info("Some secrets already deployed. They were skipped.") if cert is not None: self.secret_spec.update_refs(cert) if key is not None: self.secret_spec.update_refs(key) if chain is not None: self.secret_spec.update_refs(chain) if fc is not None: self.secret_spec.update_refs(fc)
def get_updated_ref(self, ref, candidate): # type: (SecretReference, Secret) -> None """Attempt to renew a SecretReference with a Secret. :param SecretReference ref: The old SecretReference. :param Secret candidate: The new Secret candidate. :return: A new SecretReference or 'old' if renewal was not possible. :rtype: SecretReference """ old = self.docker_client.secrets.get(ref.get("SecretID")) if SecretUtils.secret_renews(old, candidate): logger.info("--> Update %s: %s -> %s", ref.get("File").get("Name"), old.name, candidate.name) return SecretReference(candidate.id, candidate.name, ref.get("File").get("Name"), ref.get("File").get("UID"), ref.get("File").get("GID"), ref.get("File").get("Mode")) return ref
def is_secret_deployed(self, domain, name, fingerprint): # type: (str, str, str) -> bool """Check whether a secret is already deployed based on fingerprints. :param domain str: The domain the secret authenticates. :param name str: The name of the secret. :param fingerprint str: The fingerprint of the *certificate* corresponding to this secret. :return: True if deployed, False otherwise. :rtype: bool """ existing_secrets = self.get_secrets(domain, name) if len(existing_secrets) != 0: newest = existing_secrets[-1] newest_fp = SecretUtils.get_secret_fingerprint(newest) if newest_fp == fingerprint: # Skip deployment if the secret has already been deployed. return True return False
def test_secret_renews(self, secrets): a, b, c, d = [secrets[x] for x in sorted(secrets)] assert SecretUtils.secret_renews(a, b) is False assert SecretUtils.secret_renews(a, c) is False assert SecretUtils.secret_renews(a, d) is False assert SecretUtils.secret_renews(b, a) is False assert SecretUtils.secret_renews(b, c) is True assert SecretUtils.secret_renews(b, d) is False assert SecretUtils.secret_renews(c, a) is False assert SecretUtils.secret_renews(c, b) is False assert SecretUtils.secret_renews(c, d) is False assert SecretUtils.secret_renews(d, a) is False assert SecretUtils.secret_renews(d, b) is False assert SecretUtils.secret_renews(d, c) is False