chore: moved cluster issuer to ansible
diff --git a/atmosphere/flows.py b/atmosphere/flows.py
deleted file mode 100644
index e34077d..0000000
--- a/atmosphere/flows.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from taskflow import engines
-from taskflow.patterns import graph_flow
-
-from atmosphere import clients
-from atmosphere.operator.api import objects, types
-from atmosphere.tasks import constants
-from atmosphere.tasks.composite import openstack_helm
-from atmosphere.tasks.kubernetes import cert_manager
-
-
-def get_engine(config):
- api = clients.get_pykube_api()
-
- objects.Namespace(
- api=api,
- metadata=types.ObjectMeta(
- name=constants.NAMESPACE_MONITORING,
- ),
- ).apply()
-
- if config.kube_prometheus_stack.enabled:
- objects.HelmRepository(
- api=api,
- metadata=types.NamespacedObjectMeta(
- name=constants.HELM_REPOSITORY_PROMETHEUS_COMMUINTY,
- namespace=config.kube_prometheus_stack.namespace,
- ),
- spec=types.HelmRepositorySpec(
- url=constants.HELM_REPOSITORY_PROMETHEUS_COMMUINTY_URL,
- ),
- ).apply()
- objects.HelmRelease(
- api=api,
- metadata=types.NamespacedObjectMeta(
- name=constants.HELM_RELEASE_KUBE_PROMETHEUS_STACK_NAME,
- namespace=config.kube_prometheus_stack.namespace,
- ),
- spec=types.HelmReleaseSpec(
- chart=types.HelmChartTemplate(
- spec=types.HelmChartTemplateSpec(
- chart=constants.HELM_RELEASE_KUBE_PROMETHEUS_STACK_NAME,
- version=constants.HELM_RELEASE_KUBE_PROMETHEUS_STACK_VERSION,
- source_ref=types.CrossNamespaceObjectReference(
- kind="HelmRepository",
- name=constants.HELM_REPOSITORY_PROMETHEUS_COMMUINTY,
- namespace=config.kube_prometheus_stack.namespace,
- ),
- )
- ),
- values={
- **constants.HELM_RELEASE_KUBE_PROMETHEUS_STACK_VALUES,
- **config.kube_prometheus_stack.overrides,
- **{
- "alertmanager": {
- "config": openstack_helm.generate_alertmanager_config_for_opsgenie(
- config.opsgenie
- )
- }
- },
- },
- ),
- ).apply()
-
- flow = graph_flow.Flow("deploy").add(
- *cert_manager.issuer_tasks_from_config(config.issuer),
- )
- return engines.load(flow)
diff --git a/atmosphere/models/config.py b/atmosphere/models/config.py
index b0f75f5..c63e235 100644
--- a/atmosphere/models/config.py
+++ b/atmosphere/models/config.py
@@ -9,75 +9,6 @@
CONFIG_FILE = os.environ.get("ATMOSPHERE_CONFIG", "/etc/atmosphere/config.toml")
-class AcmeIssuerSolverConfig(base.Model):
- type = types.StringType(
- choices=("http", "rfc2136", "route53"), default="http", required=True
- )
-
- @classmethod
- def _claim_polymorphic(cls, data):
- return data.get("type", cls.type.default) == cls.TYPE
-
-
-class HttpAcmeIssuerSolverConfig(AcmeIssuerSolverConfig):
- TYPE = "http"
-
-
-class Rfc2136AcmeIssuerSolverConfig(AcmeIssuerSolverConfig):
- TYPE = "rfc2136"
-
- nameserver = types.StringType(required=True)
- tsig_algorithm = types.StringType(required=True)
- tsig_key_name = types.StringType(required=True)
- tsig_secret = types.StringType(required=True)
-
-
-class Route53AcmeIssuerSolverConfig(AcmeIssuerSolverConfig):
- TYPE = "route53"
-
- region = types.StringType(default="global", required=True)
- hosted_zone_id = types.StringType(required=True)
- access_key_id = types.StringType(required=True)
- secret_access_key = types.StringType(required=True)
-
-
-class Issuer(base.Model):
- type = types.StringType(
- choices=("acme", "ca", "self-signed"), default="acme", required=True
- )
-
- @classmethod
- def _claim_polymorphic(cls, data):
- return data.get("type", cls.type.default) == cls.TYPE
-
-
-class AcmeIssuerConfig(Issuer):
- TYPE = "acme"
-
- email = types.StringType(required=True)
- server = types.URLType(default="https://acme-v02.api.letsencrypt.org/directory")
- solver = types.PolyModelType(
- [
- HttpAcmeIssuerSolverConfig,
- Rfc2136AcmeIssuerSolverConfig,
- Route53AcmeIssuerSolverConfig,
- ],
- default=HttpAcmeIssuerSolverConfig(),
- required=True,
- )
-
-
-class CaIssuerConfig(Issuer):
- TYPE = "ca"
-
- certificate = types.StringType(required=True)
- private_key = types.StringType(required=True)
-
-
-class SelfSignedIssuerConfig(Issuer):
- TYPE = "self-signed"
-
-
class ChartConfig(base.Model):
enabled = types.BooleanType(default=True, required=True)
overrides = types.DictType(types.BaseType(), default={})
@@ -108,11 +39,6 @@
kube_prometheus_stack = types.ModelType(
KubePrometheusStackChartConfig, default=KubePrometheusStackChartConfig()
)
- issuer = types.PolyModelType(
- [AcmeIssuerConfig, CaIssuerConfig, SelfSignedIssuerConfig],
- default=AcmeIssuerConfig(),
- required=True,
- )
opsgenie = types.ModelType(OpsGenieConfig, default=OpsGenieConfig())
@classmethod
diff --git a/atmosphere/operator/controllers/cloud.py b/atmosphere/operator/controllers/cloud.py
index cfe28ca..573edca 100644
--- a/atmosphere/operator/controllers/cloud.py
+++ b/atmosphere/operator/controllers/cloud.py
@@ -1,14 +1,64 @@
import kopf
-from atmosphere import flows
+from atmosphere import clients
from atmosphere.models import config
-from atmosphere.operator.api import Cloud
+from atmosphere.operator.api import Cloud, objects, types
+from atmosphere.tasks import constants
+from atmosphere.tasks.composite import openstack_helm
@kopf.on.resume(Cloud.version, Cloud.kind)
@kopf.on.create(Cloud.version, Cloud.kind)
def create_fn(namespace: str, name: str, spec: dict, **_):
- # TODO(mnaser): Get rid of this flow.
cfg = config.Config.from_file()
- engine = flows.get_engine(cfg)
- engine.run()
+ api = clients.get_pykube_api()
+
+ objects.Namespace(
+ api=api,
+ metadata=types.ObjectMeta(
+ name=constants.NAMESPACE_MONITORING,
+ ),
+ ).apply()
+
+ if cfg.kube_prometheus_stack.enabled:
+ objects.HelmRepository(
+ api=api,
+ metadata=types.NamespacedObjectMeta(
+ name=constants.HELM_REPOSITORY_PROMETHEUS_COMMUINTY,
+ namespace=cfg.kube_prometheus_stack.namespace,
+ ),
+ spec=types.HelmRepositorySpec(
+ url=constants.HELM_REPOSITORY_PROMETHEUS_COMMUINTY_URL,
+ ),
+ ).apply()
+ objects.HelmRelease(
+ api=api,
+ metadata=types.NamespacedObjectMeta(
+ name=constants.HELM_RELEASE_KUBE_PROMETHEUS_STACK_NAME,
+ namespace=cfg.kube_prometheus_stack.namespace,
+ ),
+ spec=types.HelmReleaseSpec(
+ chart=types.HelmChartTemplate(
+ spec=types.HelmChartTemplateSpec(
+ chart=constants.HELM_RELEASE_KUBE_PROMETHEUS_STACK_NAME,
+ version=constants.HELM_RELEASE_KUBE_PROMETHEUS_STACK_VERSION,
+ source_ref=types.CrossNamespaceObjectReference(
+ kind="HelmRepository",
+ name=constants.HELM_REPOSITORY_PROMETHEUS_COMMUINTY,
+ namespace=cfg.kube_prometheus_stack.namespace,
+ ),
+ )
+ ),
+ values={
+ **constants.HELM_RELEASE_KUBE_PROMETHEUS_STACK_VALUES,
+ **cfg.kube_prometheus_stack.overrides,
+ **{
+ "alertmanager": {
+ "config": openstack_helm.generate_alertmanager_config_for_opsgenie(
+ cfg.opsgenie
+ )
+ }
+ },
+ },
+ ),
+ ).apply()
diff --git a/atmosphere/tasks/kubernetes/__init__.py b/atmosphere/tasks/kubernetes/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/atmosphere/tasks/kubernetes/__init__.py
+++ /dev/null
diff --git a/atmosphere/tasks/kubernetes/base.py b/atmosphere/tasks/kubernetes/base.py
deleted file mode 100644
index 838b6ad..0000000
--- a/atmosphere/tasks/kubernetes/base.py
+++ /dev/null
@@ -1,82 +0,0 @@
-import json
-import re
-
-import pykube
-import structlog
-from taskflow import task
-from tenacity import retry, stop_after_delay, wait_fixed
-
-from atmosphere import clients
-
-CAMEL_CASE_PATTERN = re.compile(r"(?<!^)(?=[A-Z])")
-LOG = structlog.get_logger()
-
-
-class ApplyKubernetesObjectTask(task.Task):
- def __init__(
- self, kind: pykube.objects.APIObject, namespace: str, name: str, *args, **kwargs
- ):
- self._obj_kind = kind
- self._obj_namespace = namespace
- self._obj_name = name
-
- kwargs["name"] = CAMEL_CASE_PATTERN.sub("-", kind.__name__).lower()
- if namespace:
- kwargs["name"] += f"-{namespace}"
- kwargs["name"] += f"-{name}"
-
- kwargs.setdefault("provides", set())
- kwargs["provides"] = kwargs["provides"].union(set([kwargs["name"]]))
-
- super().__init__(*args, **kwargs)
-
- @property
- def api(self):
- return clients.get_pykube_api()
-
- @property
- def logger(self):
- log = LOG.bind(
- kind=self._obj_kind.__name__,
- name=self._obj_name,
- )
- if self._obj_namespace:
- log = log.bind(namespace=self._obj_namespace)
- if self.requires:
- log = log.bind(requires=list(self.requires))
- return log
-
- def generate_object(self, *args, **kwargs) -> pykube.objects.APIObject:
- raise NotImplementedError
-
- def wait_for_resource(self, resource: pykube.objects.APIObject):
- pass
-
- @retry(wait=wait_fixed(2), stop=stop_after_delay(120))
- def execute(self, *args, **kwargs):
- self.logger.debug("Ensuring resource")
-
- resource = self.generate_object()
- resp = resource.api.patch(
- **resource.api_kwargs(
- headers={
- "Content-Type": "application/apply-patch+yaml",
- },
- params={
- "fieldManager": "atmosphere-operator",
- "force": True,
- },
- data=json.dumps(resource.obj),
- )
- )
-
- resource.api.raise_for_status(resp)
- resource.set_obj(resp.json())
-
- self.wait_for_resource(resource)
-
- self.logger.info("Ensured resource")
-
- return {
- self.name: resource,
- }
diff --git a/atmosphere/tasks/kubernetes/cert_manager.py b/atmosphere/tasks/kubernetes/cert_manager.py
deleted file mode 100644
index 2c420a3..0000000
--- a/atmosphere/tasks/kubernetes/cert_manager.py
+++ /dev/null
@@ -1,200 +0,0 @@
-import pykube
-
-from atmosphere.models import config
-from atmosphere.tasks import constants
-from atmosphere.tasks.kubernetes import base, v1
-
-
-class Certificate(pykube.objects.NamespacedAPIObject):
- version = "cert-manager.io/v1"
- endpoint = "certificates"
- kind = "Certificate"
-
-
-class ApplyCertificateTask(base.ApplyKubernetesObjectTask):
- def __init__(self, namespace: str, name: str, spec: dict):
- self._spec = spec
-
- super().__init__(
- kind=Certificate,
- namespace=namespace,
- name=name,
- )
-
- def generate_object(self) -> Certificate:
- return Certificate(
- self.api,
- {
- "apiVersion": self._obj_kind.version,
- "kind": self._obj_kind.kind,
- "metadata": {
- "name": self._obj_name,
- "namespace": self._obj_namespace,
- },
- "spec": self._spec,
- },
- )
-
-
-class ClusterIssuer(pykube.objects.APIObject):
- version = "cert-manager.io/v1"
- endpoint = "clusterissuers"
- kind = "ClusterIssuer"
-
-
-class ApplyClusterIssuerTask(base.ApplyKubernetesObjectTask):
- def __init__(self, name: str, spec: dict):
- self._spec = spec
-
- super().__init__(
- kind=ClusterIssuer,
- namespace=None,
- name=name,
- )
-
- def generate_object(self) -> ClusterIssuer:
- return ClusterIssuer(
- self.api,
- {
- "apiVersion": self._obj_kind.version,
- "kind": self._obj_kind.kind,
- "metadata": {
- "name": self._obj_name,
- },
- "spec": self._spec,
- },
- )
-
-
-def issuer_tasks_from_config(config: config.Issuer) -> list:
- objects = [
- ApplyClusterIssuerTask(
- name="self-signed",
- spec={
- "selfSigned": {},
- },
- )
- ]
-
- if config.type == "acme":
- spec = {
- "acme": {
- "email": config.email,
- "server": config.server,
- "privateKeySecretRef": {
- "name": "cert-manager-issuer-account-key",
- },
- },
- }
-
- if config.solver.type == "http":
- spec["acme"]["solvers"] = [
- {
- "http01": {
- "ingress": {
- "class": "openstack",
- },
- },
- },
- ]
- elif config.solver.type == "rfc2136":
- # NOTE(mnaser): We have to create a secret containing the AWS
- # credentials in this case.
- objects.append(
- v1.ApplySecretTask(
- constants.NAMESPACE_CERT_MANAGER,
- "cert-manager-issuer-tsig-secret-key",
- data={
- "tsig-secret-key": config.solver.tsig_secret,
- },
- )
- )
-
- spec["acme"]["solvers"] = [
- {
- "dns01": {
- "rfc2136": {
- "nameserver": config.solver.nameserver,
- "tsigAlgorithm": config.solver.tsig_algorithm,
- "tsigKeyName": config.solver.tsig_key_name,
- "tsigSecretSecretRef": {
- "name": "cert-manager-issuer-tsig-secret-key",
- "key": "tsig-secret-key",
- },
- },
- },
- },
- ]
- elif config.solver.type == "route53":
- # NOTE(mnaser): We have to create a secret containing the AWS
- # credentials in this case.
- objects.append(
- v1.ApplySecretTask(
- constants.NAMESPACE_CERT_MANAGER,
- "cert-manager-issuer-route53-credentials",
- data={"secret-access-key": config.solver.secret_access_key},
- )
- )
-
- spec["acme"]["solvers"] = [
- {
- "dns01": {
- "route53": {
- "region": config.solver.region,
- "hostedZoneID": config.solver.hosted_zone_id,
- "accessKeyID": config.solver.access_key_id,
- "secretAccessKeySecretRef": {
- "name": "cert-manager-issuer-route53-credentials",
- "key": "secret-access-key",
- },
- },
- },
- },
- ]
- elif config.type == "ca":
- # NOTE(mnaser): We have to create a secret containing the CA
- # certificate and key in this case.
- objects.append(
- v1.ApplySecretTask(
- constants.NAMESPACE_CERT_MANAGER,
- "cert-manager-issuer-ca",
- data={
- "tls.crt": config.certificate,
- "tls.key": config.private_key,
- },
- )
- )
-
- spec = {
- "ca": {
- "secretName": "cert-manager-issuer-ca",
- }
- }
- elif config.type == "self-signed":
- # NOTE(mnaser): We have to setup the self-signed CA in this case
- objects += [
- ApplyCertificateTask(
- namespace=constants.NAMESPACE_CERT_MANAGER,
- name="self-signed-ca",
- spec={
- "isCA": True,
- "commonName": "selfsigned-ca",
- "secretName": "cert-manager-selfsigned-ca",
- "duration": "86400h",
- "renewBefore": "360h",
- "privateKey": {"algorithm": "ECDSA", "size": 256},
- "issuerRef": {
- "kind": "ClusterIssuer",
- "name": "self-signed",
- },
- },
- ),
- ]
-
- spec = {
- "ca": {
- "secretName": "cert-manager-selfsigned-ca",
- }
- }
-
- return objects + [ApplyClusterIssuerTask(name="atmosphere", spec=spec)]
diff --git a/atmosphere/tasks/kubernetes/v1.py b/atmosphere/tasks/kubernetes/v1.py
deleted file mode 100644
index cd48196..0000000
--- a/atmosphere/tasks/kubernetes/v1.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import pykube
-
-from atmosphere.tasks.kubernetes import base
-
-
-class ApplySecretTask(base.ApplyKubernetesObjectTask):
- def __init__(self, namespace: str, name: str, data: str):
- self._data = data
-
- super().__init__(
- kind=pykube.Secret,
- namespace=namespace,
- name=name,
- )
-
- def generate_object(self) -> pykube.Secret:
- return pykube.Secret(
- self.api,
- {
- "apiVersion": "v1",
- "kind": "Secret",
- "metadata": {
- "name": self._obj_name,
- "namespace": self._obj_namespace,
- },
- "stringData": self._data,
- },
- )
diff --git a/atmosphere/tests/unit/tasks/kubernetes/test_cert_manager.py b/atmosphere/tests/unit/tasks/kubernetes/test_cert_manager.py
deleted file mode 100644
index 1f03439..0000000
--- a/atmosphere/tests/unit/tasks/kubernetes/test_cert_manager.py
+++ /dev/null
@@ -1,335 +0,0 @@
-import textwrap
-
-import pykube
-import pytest
-
-from atmosphere.models import config
-from atmosphere.tasks import constants
-from atmosphere.tasks.kubernetes import cert_manager
-
-
-@pytest.mark.parametrize(
- "cfg_data,expected",
- [
- pytest.param(
- textwrap.dedent(
- """\
- [issuer]
- email = "mnaser@vexxhost.com"
- """
- ),
- [
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "self-signed",
- },
- "spec": {
- "selfSigned": {},
- },
- },
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "atmosphere",
- },
- "spec": {
- "acme": {
- "email": "mnaser@vexxhost.com",
- "server": "https://acme-v02.api.letsencrypt.org/directory",
- "privateKeySecretRef": {
- "name": "cert-manager-issuer-account-key",
- },
- "solvers": [
- {
- "http01": {
- "ingress": {
- "class": "openstack",
- },
- },
- },
- ],
- },
- },
- },
- ],
- id="default",
- ),
- pytest.param(
- textwrap.dedent(
- """\
- [issuer]
- email = "mnaser@vexxhost.com"
-
- [issuer.solver]
- type = "rfc2136"
- nameserver = "1.2.3.4:53"
- tsig_algorithm = "hmac-sha256"
- tsig_key_name = "foobar"
- tsig_secret = "secret123"
- """
- ),
- [
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "self-signed",
- },
- "spec": {
- "selfSigned": {},
- },
- },
- {
- "apiVersion": pykube.Secret.version,
- "kind": pykube.Secret.kind,
- "metadata": {
- "name": "cert-manager-issuer-tsig-secret-key",
- "namespace": constants.NAMESPACE_CERT_MANAGER,
- },
- "stringData": {
- "tsig-secret-key": "secret123",
- },
- },
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "atmosphere",
- },
- "spec": {
- "acme": {
- "email": "mnaser@vexxhost.com",
- "server": "https://acme-v02.api.letsencrypt.org/directory",
- "privateKeySecretRef": {
- "name": "cert-manager-issuer-account-key",
- },
- "solvers": [
- {
- "dns01": {
- "rfc2136": {
- "nameserver": "1.2.3.4:53",
- "tsigAlgorithm": "hmac-sha256",
- "tsigKeyName": "foobar",
- "tsigSecretSecretRef": {
- "name": "cert-manager-issuer-tsig-secret-key",
- "key": "tsig-secret-key",
- },
- },
- },
- },
- ],
- },
- },
- },
- ],
- id="rfc2136",
- ),
- pytest.param(
- textwrap.dedent(
- """\
- [issuer]
- email = "mnaser@vexxhost.com"
-
- [issuer.solver]
- type = "route53"
- hosted_zone_id = "Z3A4X2Y2Y3"
- access_key_id = "AKIAIOSFODNN7EXAMPLE"
- secret_access_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
- """
- ),
- [
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "self-signed",
- },
- "spec": {
- "selfSigned": {},
- },
- },
- {
- "apiVersion": pykube.Secret.version,
- "kind": pykube.Secret.kind,
- "metadata": {
- "name": "cert-manager-issuer-route53-credentials",
- "namespace": constants.NAMESPACE_CERT_MANAGER,
- },
- "stringData": {
- "secret-access-key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
- },
- },
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "atmosphere",
- },
- "spec": {
- "acme": {
- "email": "mnaser@vexxhost.com",
- "server": "https://acme-v02.api.letsencrypt.org/directory",
- "privateKeySecretRef": {
- "name": "cert-manager-issuer-account-key",
- },
- "solvers": [
- {
- "dns01": {
- "route53": {
- "region": "global",
- "hostedZoneID": "Z3A4X2Y2Y3",
- "accessKeyID": "AKIAIOSFODNN7EXAMPLE",
- "secretAccessKeySecretRef": {
- "name": "cert-manager-issuer-route53-credentials",
- "key": "secret-access-key",
- },
- },
- },
- },
- ],
- },
- },
- },
- ],
- id="route53",
- ),
- pytest.param(
- textwrap.dedent(
- """\
- [issuer]
- type = "ca"
- certificate = '''
- -----BEGIN CERTIFICATE-----
- MIIDBjCCAe4CCQDQ3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
- VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
- ...
- -----END CERTIFICATE-----
- '''
- private_key = '''
- -----BEGIN RSA PRIVATE KEY-----
- MIIEpAIBAAKCAQEAw3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
- VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
- ...
- -----END RSA PRIVATE KEY-----
- '''
- """
- ),
- [
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "self-signed",
- },
- "spec": {
- "selfSigned": {},
- },
- },
- {
- "apiVersion": pykube.Secret.version,
- "kind": pykube.Secret.kind,
- "metadata": {
- "name": "cert-manager-issuer-ca",
- "namespace": constants.NAMESPACE_CERT_MANAGER,
- },
- "stringData": {
- "tls.crt": textwrap.dedent(
- """\
- -----BEGIN CERTIFICATE-----
- MIIDBjCCAe4CCQDQ3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
- VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
- ...
- -----END CERTIFICATE-----
- """
- ),
- "tls.key": textwrap.dedent(
- """\
- -----BEGIN RSA PRIVATE KEY-----
- MIIEpAIBAAKCAQEAw3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
- VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
- ...
- -----END RSA PRIVATE KEY-----
- """
- ),
- },
- },
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "atmosphere",
- },
- "spec": {
- "ca": {
- "secretName": "cert-manager-issuer-ca",
- },
- },
- },
- ],
- id="ca",
- ),
- pytest.param(
- textwrap.dedent(
- """\
- [issuer]
- type = "self-signed"
- """
- ),
- [
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "self-signed",
- },
- "spec": {
- "selfSigned": {},
- },
- },
- {
- "apiVersion": cert_manager.Certificate.version,
- "kind": cert_manager.Certificate.kind,
- "metadata": {
- "name": "self-signed-ca",
- "namespace": constants.NAMESPACE_CERT_MANAGER,
- },
- "spec": {
- "isCA": True,
- "commonName": "selfsigned-ca",
- "secretName": "cert-manager-selfsigned-ca",
- "duration": "86400h",
- "renewBefore": "360h",
- "privateKey": {"algorithm": "ECDSA", "size": 256},
- "issuerRef": {
- "kind": "ClusterIssuer",
- "name": "self-signed",
- },
- },
- },
- {
- "apiVersion": cert_manager.ClusterIssuer.version,
- "kind": cert_manager.ClusterIssuer.kind,
- "metadata": {
- "name": "atmosphere",
- },
- "spec": {
- "ca": {
- "secretName": "cert-manager-selfsigned-ca",
- },
- },
- },
- ],
- id="self-signed",
- ),
- ],
-)
-def test_apply_issuer_task_from_config(pykube, cfg_data, expected):
- cfg = config.Config.from_string(cfg_data, validate=False)
- cfg.issuer.validate()
- assert [
- t.generate_object().obj
- for t in cert_manager.issuer_tasks_from_config(cfg.issuer)
- ] == expected
diff --git a/docs/certificates.md b/docs/certificates.md
deleted file mode 100644
index d069b3a..0000000
--- a/docs/certificates.md
+++ /dev/null
@@ -1,114 +0,0 @@
-# Certificates
-
-Atmosphere simplifies all the management of your SSL certificates for all of
-your API endpoints by automatically issuing and renewing certificates for you.
-
-## ACME
-
-Atmosphere uses the [ACME](https://tools.ietf.org/html/rfc8555) protocol by
-default to request certificates from [LetsEncrypt](https://letsencrypt.org/).
-
-This is configured to work out of the box if your APIs are publicly accessible,
-you just need to configure an email address.
-
-```yaml
-atmosphere_issuer_config:
- email: foo@bar.com
-```
-
-If you're running your own internal ACME server, you can configure Atmosphere to
-point towards it by setting the `server` field.
-
-```yaml
-atmosphere_issuer_config:
- email: foo@bar.com
- server: https://acme.example.com
-```
-
-### DNS-01 challenges
-
-Atmosphere uses the `HTTP-01` solver by default, which means that as long as
-your ACME server can reach your API, you don't need to do anything else.
-
-If your ACME server cannot reach your API, you will need to use the DNS-01
-challenges which require you to configure your DNS provider.
-
-#### RFC2136
-
-If you have DNS server that supports RFC2136, you can use it to solve the DNS
-challenges, you can use the following configuration:
-
-```yaml
-atmosphere_issuer_config:
- email: foo@bar.com
- solver:
- type: rfc2136
- nameserver: <NAMESERVER>:<PORT>
- tsig_algorithm: <ALGORITHM>
- tsig_key_name: <NAME>
- tsig_secret: <SECRET>
-```
-
-#### Route53
-
-If you are using Route53 to host the DNS for your domains, you can use the
-following configuration:
-
-```yaml
-atmosphere_issuer_config:
- email: foo@bar.com
- solver:
- type: route53
- hosted_zone_id: <HOSTED_ZONE_ID>
- access_key_id: <AWS_ACCESS_KEY_ID>
- secret_access_key: <AWS_SECRET_ACCESS_KEY>
-```
-
-!!! note
-
- You'll need to make sure that your AWS credentials have the correct
- permissions to update the Route53 zone.
-
-## Using pre-existing CA
-
-If you have an existing CA that you'd like to use with Atmosphere, you can
-simply configure it by including the certificate and private key:
-
-```yaml
-atmosphere_issuer_config:
- type: ca
- certificate: |
- -----BEGIN CERTIFICATE-----
- MIIDBjCCAe4CCQDQ3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
- VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
- ...
- -----END CERTIFICATE-----
- private_key: |
- -----BEGIN RSA PRIVATE KEY-----
- MIIEpAIBAAKCAQEAw3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
- VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
- ...
- -----END RSA PRIVATE KEY-----
-```
-
-!!! note
-
- If your issuer is an intermediate certificate, you will need to ensure that
- they `certificate` key includes the full chain in the correct order of issuer,
- intermediate(s) then root.
-
-## Self-signed certificates
-
-If you are in an environment which does not have a trusted certificate authority
-and it does not have access to the internet to be able to use LetsEncrypt, you
-can use self-signed certificates by adding the following to your inventory:
-
-```yaml
-atmosphere_issuer_config:
- type: self-signed
-```
-
-!!! warning
-
- Self-signed certificates are not recommended for production environments,
- they are only recommended for development and testing environments.
diff --git a/molecule/default/group_vars/all/molecule.yml b/molecule/default/group_vars/all/molecule.yml
index 6fecc77..f07d9b3 100644
--- a/molecule/default/group_vars/all/molecule.yml
+++ b/molecule/default/group_vars/all/molecule.yml
@@ -1,7 +1,6 @@
atmosphere_image: "{{ lookup('file', lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') + '/image') }}"
-atmosphere_issuer_config:
- type: self-signed
+cluster_issuer_type: self-signed
openstack_helm_glance_images:
- name: cirros
diff --git a/poetry.lock b/poetry.lock
index fd93322..ba01ff2 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -106,18 +106,6 @@
tests_no_zope = ["cloudpickle", "hypothesis", "mypy (>=0.971,<0.990)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
[[package]]
-name = "automaton"
-version = "3.0.1"
-description = "Friendly state machines for python."
-category = "main"
-optional = true
-python-versions = ">=3.8"
-
-[package.dependencies]
-pbr = ">=2.0.0,<2.1.0 || >2.1.0"
-PrettyTable = ">=0.7.2"
-
-[[package]]
name = "binaryornot"
version = "0.4.4"
description = "Ultra-lightweight pure Python package to check if a file is binary or text."
@@ -129,14 +117,6 @@
chardet = ">=3.0.2"
[[package]]
-name = "cachetools"
-version = "5.3.0"
-description = "Extensible memoizing collections and decorators"
-category = "main"
-optional = true
-python-versions = "~=3.7"
-
-[[package]]
name = "certifi"
version = "2022.12.7"
description = "Python package for providing Mozilla's CA Bundle."
@@ -262,7 +242,7 @@
version = "2.5.0"
description = "A collection of Python deprecation patterns and strategies that help you collect your technical debt in a non-destructive manner."
category = "main"
-optional = true
+optional = false
python-versions = ">=3.6"
[package.dependencies]
@@ -336,14 +316,6 @@
testing = ["pre-commit"]
[[package]]
-name = "fasteners"
-version = "0.18"
-description = "A python package that provides useful locks"
-category = "main"
-optional = true
-python-versions = ">=3.6"
-
-[[package]]
name = "flake8"
version = "5.0.4"
description = "the modular source code checker: pep8 pyflakes and co"
@@ -380,14 +352,6 @@
python-versions = ">=3.7"
[[package]]
-name = "futurist"
-version = "2.4.1"
-description = "Useful additions to futures, from the future."
-category = "main"
-optional = true
-python-versions = ">=3.6"
-
-[[package]]
name = "ghp-import"
version = "2.1.0"
description = "Copy your docs directly to the gh-pages branch."
@@ -533,7 +497,7 @@
name = "jsonschema"
version = "4.17.3"
description = "An implementation of JSON Schema validation for Python"
-category = "main"
+category = "dev"
optional = false
python-versions = ">=3.7"
@@ -737,7 +701,7 @@
version = "1.0.4"
description = "MessagePack serializer"
category = "main"
-optional = true
+optional = false
python-versions = "*"
[[package]]
@@ -768,7 +732,7 @@
version = "0.8.0"
description = "A network address manipulation library for Python"
category = "main"
-optional = true
+optional = false
python-versions = "*"
[[package]]
@@ -780,21 +744,6 @@
python-versions = "*"
[[package]]
-name = "networkx"
-version = "3.0"
-description = "Python package for creating and manipulating graphs and networks"
-category = "main"
-optional = true
-python-versions = ">=3.8"
-
-[package.extras]
-default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"]
-developer = ["mypy (>=0.991)", "pre-commit (>=2.20)"]
-doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.2)", "pydata-sphinx-theme (>=0.11)", "sphinx (==5.2.3)", "sphinx-gallery (>=0.11)", "texext (>=0.6.7)"]
-extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"]
-test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"]
-
-[[package]]
name = "openstacksdk"
version = "0.61.0"
description = "An SDK for building applications to work with OpenStack"
@@ -834,7 +783,7 @@
version = "5.1.0"
description = "Oslo i18n library"
category = "main"
-optional = true
+optional = false
python-versions = ">=3.6"
[package.dependencies]
@@ -845,7 +794,7 @@
version = "5.0.0"
description = "Oslo Serialization library"
category = "main"
-optional = true
+optional = false
python-versions = ">=3.8"
[package.dependencies]
@@ -859,7 +808,7 @@
version = "6.1.0"
description = "Oslo Utility library"
category = "main"
-optional = true
+optional = false
python-versions = ">=3.8"
[package.dependencies]
@@ -901,20 +850,6 @@
testing = ["pytest", "pytest-benchmark"]
[[package]]
-name = "prettytable"
-version = "3.6.0"
-description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format"
-category = "main"
-optional = true
-python-versions = ">=3.7"
-
-[package.dependencies]
-wcwidth = "*"
-
-[package.extras]
-tests = ["pytest", "pytest-cov", "pytest-lazy-fixture"]
-
-[[package]]
name = "py"
version = "1.11.0"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
@@ -954,17 +889,6 @@
email = ["email-validator (>=1.0.3)"]
[[package]]
-name = "pydot"
-version = "1.4.2"
-description = "Python interface to Graphviz's Dot"
-category = "main"
-optional = true
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-
-[package.dependencies]
-pyparsing = ">=2.1.4"
-
-[[package]]
name = "pyflakes"
version = "2.5.0"
description = "passive checker of Python programs"
@@ -1016,7 +940,7 @@
version = "3.0.9"
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
category = "main"
-optional = true
+optional = false
python-versions = ">=3.6.8"
[package.extras]
@@ -1026,7 +950,7 @@
name = "pyrsistent"
version = "0.19.3"
description = "Persistent/Functional/Immutable data structures"
-category = "main"
+category = "dev"
optional = false
python-versions = ">=3.7"
@@ -1146,7 +1070,7 @@
version = "2022.7.1"
description = "World timezone definitions, modern and historical"
category = "main"
-optional = true
+optional = false
python-versions = "*"
[[package]]
@@ -1284,20 +1208,6 @@
pbr = ">=2.0.0,<2.1.0 || >2.1.0"
[[package]]
-name = "structlog"
-version = "22.3.0"
-description = "Structured Logging for Python"
-category = "main"
-optional = true
-python-versions = ">=3.7"
-
-[package.extras]
-dev = ["structlog[docs,tests,typing]"]
-docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "twisted"]
-tests = ["coverage[toml]", "freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"]
-typing = ["mypy", "rich", "twisted"]
-
-[[package]]
name = "subprocess-tee"
version = "0.4.1"
description = "subprocess-tee"
@@ -1309,47 +1219,6 @@
test = ["enrich (>=1.2.6)", "molecule (>=3.4.0)", "pytest (>=6.2.5)", "pytest-cov (>=2.12.1)", "pytest-plus (>=0.2)", "pytest-xdist (>=2.3.0)"]
[[package]]
-name = "taskflow"
-version = "5.1.0"
-description = "Taskflow structured state management library."
-category = "main"
-optional = true
-python-versions = ">=3.8"
-
-[package.dependencies]
-automaton = ">=1.9.0"
-cachetools = ">=2.0.0"
-fasteners = ">=0.17.3"
-futurist = ">=1.2.0"
-jsonschema = ">=3.2.0"
-networkx = ">=2.1.0"
-"oslo.serialization" = ">=2.18.0,<2.19.1 || >2.19.1"
-"oslo.utils" = ">=3.33.0"
-pbr = ">=2.0.0,<2.1.0 || >2.1.0"
-pydot = ">=1.2.4"
-stevedore = ">=1.20.0"
-tenacity = ">=6.0.0"
-
-[package.extras]
-database = ["PyMySQL (>=0.7.6)", "SQLAlchemy (>=1.0.10,!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8)", "SQLAlchemy-Utils (>=0.30.11)", "alembic (>=0.8.10)", "psycopg2 (>=2.8.0)"]
-eventlet = ["eventlet (>=0.18.2,!=0.18.3,!=0.20.1,!=0.21.0)"]
-redis = ["redis (>=2.10.0)"]
-test = ["hacking (>=0.10.0,<0.11)", "mock (>=2.0.0)", "oslotest (>=3.2.0)", "pydotplus (>=2.0.2)", "stestr (>=2.0.0)", "testscenarios (>=0.4)", "testtools (>=2.2.0)"]
-workers = ["kombu (>=4.3.0)"]
-zookeeper = ["kazoo (>=2.6.0)", "zake (>=0.1.6)"]
-
-[[package]]
-name = "tenacity"
-version = "8.1.0"
-description = "Retry code until it succeeds"
-category = "main"
-optional = true
-python-versions = ">=3.6"
-
-[package.extras]
-doc = ["reno", "sphinx", "tornado (>=4.5)"]
-
-[[package]]
name = "text-unidecode"
version = "1.3"
description = "The most basic Text::Unidecode port"
@@ -1435,19 +1304,11 @@
watchmedo = ["PyYAML (>=3.10)"]
[[package]]
-name = "wcwidth"
-version = "0.2.6"
-description = "Measures the displayed width of unicode strings in a terminal"
-category = "main"
-optional = true
-python-versions = "*"
-
-[[package]]
name = "wrapt"
version = "1.14.1"
description = "Module for decorators, wrappers and monkey patching."
category = "main"
-optional = true
+optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]]
@@ -1463,12 +1324,12 @@
multidict = ">=4.0"
[extras]
-operator = ["schematics", "pydantic", "pykube-ng", "structlog", "taskflow", "tomli", "jsonnet", "kopf"]
+operator = ["schematics", "pydantic", "pykube-ng", "tomli", "jsonnet", "kopf"]
[metadata]
lock-version = "1.1"
python-versions = "^3.10"
-content-hash = "2192157ba411e6a12715305b5496b609422c1b04208dac823c3729d2aab802df"
+content-hash = "034ac062f5dca8bb749b33d8a4cd4d646a41e7c0da24771ea1522041fa183413"
[metadata.files]
aiohttp = [
@@ -1588,18 +1449,10 @@
{file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
{file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
]
-automaton = [
- {file = "automaton-3.0.1-py3-none-any.whl", hash = "sha256:bb5d2f385accbe3724cbd2c28808d7d69375b09a6c03e8e3ef2980df20929c6e"},
- {file = "automaton-3.0.1.tar.gz", hash = "sha256:1004a4787c241a62ccab255c414207b93f5fdc8509a022590d05bdeb3807cb76"},
-]
binaryornot = [
{file = "binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4"},
{file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"},
]
-cachetools = [
- {file = "cachetools-5.3.0-py3-none-any.whl", hash = "sha256:429e1a1e845c008ea6c85aa35d4b98b65d6a9763eeef3e37e92728a12d1de9d4"},
- {file = "cachetools-5.3.0.tar.gz", hash = "sha256:13dfddc7b8df938c21a940dfa6557ce6e94a2f1cdfa58eb90c805721d58f2c14"},
-]
certifi = [
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
@@ -1800,10 +1653,6 @@
{file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"},
{file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"},
]
-fasteners = [
- {file = "fasteners-0.18-py3-none-any.whl", hash = "sha256:1d4caf5f8db57b0e4107d94fd5a1d02510a450dced6ca77d1839064c1bacf20c"},
- {file = "fasteners-0.18.tar.gz", hash = "sha256:cb7c13ef91e0c7e4fe4af38ecaf6b904ec3f5ce0dda06d34924b6b74b869d953"},
-]
flake8 = [
{file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"},
{file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"},
@@ -1888,10 +1737,6 @@
{file = "frozenlist-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9"},
{file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"},
]
-futurist = [
- {file = "futurist-2.4.1-py3-none-any.whl", hash = "sha256:3ef3a1f63eca3c4f6ebc8f4cff0bb1492241a0df93622e0bf3e6e90ca822e0e0"},
- {file = "futurist-2.4.1.tar.gz", hash = "sha256:9c1760a877c0fe3260d04b6a6d4352a6d25ac58e483f1d6cd495e33dc3740ff7"},
-]
ghp-import = [
{file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"},
{file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"},
@@ -2209,10 +2054,6 @@
{file = "netifaces-0.11.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e76c7f351e0444721e85f975ae92718e21c1f361bda946d60a214061de1f00a1"},
{file = "netifaces-0.11.0.tar.gz", hash = "sha256:043a79146eb2907edf439899f262b3dfe41717d34124298ed281139a8b93ca32"},
]
-networkx = [
- {file = "networkx-3.0-py3-none-any.whl", hash = "sha256:58058d66b1818043527244fab9d41a51fcd7dcc271748015f3c181b8a90c8e2e"},
- {file = "networkx-3.0.tar.gz", hash = "sha256:9a9992345353618ae98339c2b63d8201c381c2944f38a2ab49cb45a4c667e412"},
-]
openstacksdk = [
{file = "openstacksdk-0.61.0-py3-none-any.whl", hash = "sha256:9894d3d510563dcfc50c4755287dbfbf98def1f37caf2cfc15e9d0e1fd5d9a41"},
{file = "openstacksdk-0.61.0.tar.gz", hash = "sha256:3eed308871230f0c53a8f58b6c5a358b184080c6b2c6bc69ab088eea057aa127"},
@@ -2245,10 +2086,6 @@
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
]
-prettytable = [
- {file = "prettytable-3.6.0-py3-none-any.whl", hash = "sha256:3b767129491767a3a5108e6f305cbaa650f8020a7db5dfe994a2df7ef7bad0fe"},
- {file = "prettytable-3.6.0.tar.gz", hash = "sha256:2e0026af955b4ea67b22122f310b90eae890738c08cb0458693a49b6221530ac"},
-]
py = [
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
@@ -2299,10 +2136,6 @@
{file = "pydantic-1.10.4-py3-none-any.whl", hash = "sha256:4948f264678c703f3877d1c8877c4e3b2e12e549c57795107f08cf70c6ec7774"},
{file = "pydantic-1.10.4.tar.gz", hash = "sha256:b9a3859f24eb4e097502a3be1fb4b2abb79b6103dd9e2e0edb70613a4459a648"},
]
-pydot = [
- {file = "pydot-1.4.2-py2.py3-none-any.whl", hash = "sha256:66c98190c65b8d2e2382a441b4c0edfdb4f4c025ef9cb9874de478fb0793a451"},
- {file = "pydot-1.4.2.tar.gz", hash = "sha256:248081a39bcb56784deb018977e428605c1c758f10897a339fce1dd728ff007d"},
-]
pyflakes = [
{file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"},
{file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"},
@@ -2560,22 +2393,10 @@
{file = "stevedore-4.1.1-py3-none-any.whl", hash = "sha256:aa6436565c069b2946fe4ebff07f5041e0c8bf18c7376dd29edf80cf7d524e4e"},
{file = "stevedore-4.1.1.tar.gz", hash = "sha256:7f8aeb6e3f90f96832c301bff21a7eb5eefbe894c88c506483d355565d88cc1a"},
]
-structlog = [
- {file = "structlog-22.3.0-py3-none-any.whl", hash = "sha256:b403f344f902b220648fa9f286a23c0cc5439a5844d271fec40562dbadbc70ad"},
- {file = "structlog-22.3.0.tar.gz", hash = "sha256:e7509391f215e4afb88b1b80fa3ea074be57a5a17d794bd436a5c949da023333"},
-]
subprocess-tee = [
{file = "subprocess-tee-0.4.1.tar.gz", hash = "sha256:b3c124993f8b88d1eb1c2fde0bc2069787eac720ba88771cba17e8c93324825d"},
{file = "subprocess_tee-0.4.1-py3-none-any.whl", hash = "sha256:eca56973a1c1237093c2055b2731bcaab784683b83f22c76f26e4c5763402e28"},
]
-taskflow = [
- {file = "taskflow-5.1.0-py3-none-any.whl", hash = "sha256:cf845dd9fe7daea755f4d4211bfe3eac20bc842ac15a858846d1aa9cf14aa066"},
- {file = "taskflow-5.1.0.tar.gz", hash = "sha256:ec9028486b7e233fb790f30fa07b9e82fc6bd5d56a8cff99f378fd1d567180d0"},
-]
-tenacity = [
- {file = "tenacity-8.1.0-py3-none-any.whl", hash = "sha256:35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac"},
- {file = "tenacity-8.1.0.tar.gz", hash = "sha256:e48c437fdf9340f5666b92cd7990e96bc5fc955e1298baf4a907e3972067a445"},
-]
text-unidecode = [
{file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"},
{file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"},
@@ -2666,10 +2487,6 @@
{file = "watchdog-2.2.1-py3-none-win_ia64.whl", hash = "sha256:195ab1d9d611a4c1e5311cbf42273bc541e18ea8c32712f2fb703cfc6ff006f9"},
{file = "watchdog-2.2.1.tar.gz", hash = "sha256:cdcc23c9528601a8a293eb4369cbd14f6b4f34f07ae8769421252e9c22718b6f"},
]
-wcwidth = [
- {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
- {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
-]
wrapt = [
{file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"},
{file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"},
diff --git a/pyproject.toml b/pyproject.toml
index dc15848..6948ea2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,13 +13,12 @@
pydantic = { version = "^1.10.4", optional = true }
schematics = { version = "^2.1.1", optional = true }
pykube-ng = { version = "^22.7.0", optional = true }
-structlog = { version = "^22.1.0", optional = true }
-taskflow = { version = "^5.0.0", optional = true }
tomli = { version = "^2.0.1", optional = true }
jsonnet = { version = "^0.18.0", optional = true }
kopf = { version = "^1.36.0", optional = true, extras = ["uvloop"] }
openstacksdk = "<0.99.0"
docker-image-py = "^0.1.12"
+"oslo.serialization" = "^5.0.0"
[tool.poetry.extras]
operator = [
diff --git a/roles/atmosphere/defaults/main.yml b/roles/atmosphere/defaults/main.yml
index 3d09da7..377ff32 100644
--- a/roles/atmosphere/defaults/main.yml
+++ b/roles/atmosphere/defaults/main.yml
@@ -4,7 +4,6 @@
image_repository: "{{ atmosphere_image_repository | default('') }}"
kube_prometheus_stack:
overrides: "{{ kube_prometheus_stack_values | default({}) }}"
- issuer: "{{ atmosphere_issuer_config }}"
opsgenie: "{{ atmosphere_opsgenie_config | default({}) }}"
atmosphere_cloud_spec: {}
diff --git a/roles/certificates/README.md b/roles/certificates/README.md
deleted file mode 100644
index 141cc1b..0000000
--- a/roles/certificates/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# `certificates`
-
-!!! warning
-
- This is a legacy role that is meant to be phased out eventually when there
- is no need for the control-plane systems to have the CA installed on them.
diff --git a/roles/certificates/tasks/main.yml b/roles/certificates/tasks/main.yml
deleted file mode 100644
index e47b897..0000000
--- a/roles/certificates/tasks/main.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-- name: Bootstrap PKI
- when:
- - atmosphere_issuer_config.type is defined
- - atmosphere_issuer_config.type in ("self-signed", "ca")
- block:
- - name: Wait till the secret is created
- kubernetes.core.k8s_info:
- api_version: v1
- kind: Secret
- name: "{{ (atmosphere_issuer_config.type == 'self-signed') | ternary('cert-manager-selfsigned-ca', 'cert-manager-issuer-ca') }}"
- namespace: cert-manager
- wait: true
- wait_sleep: 1
- wait_timeout: 600
- register: _openstack_helm_root_secret
-
- - name: Copy CA certificate on host
- ansible.builtin.copy:
- content: "{{ _openstack_helm_root_secret.resources[0].data['tls.crt'] | b64decode }}"
- dest: "/usr/local/share/ca-certificates/self-signed-osh-ca.crt"
- mode: "0644"
-
- - name: Update CA certificates on host
- ansible.builtin.command:
- cmd: update-ca-certificates
- changed_when: false
diff --git a/roles/cluster_issuer/README.md b/roles/cluster_issuer/README.md
new file mode 100644
index 0000000..fe9259c
--- /dev/null
+++ b/roles/cluster_issuer/README.md
@@ -0,0 +1,107 @@
+# `cluster_issuer`
+
+Atmosphere simplifies all the management of your SSL certificates for all of
+your API endpoints by automatically issuing and renewing certificates for you.
+
+## ACME
+
+Atmosphere uses the [ACME](https://tools.ietf.org/html/rfc8555) protocol by
+default to request certificates from [LetsEncrypt](https://letsencrypt.org/).
+
+This is configured to work out of the box if your APIs are publicly accessible,
+you just need to configure an email address.
+
+```yaml
+cluster_issuer_acme_email: user@example.com
+```
+
+If you're running your own internal ACME server, you can configure Atmosphere to
+point towards it by setting the `cluster_issuer_acme_server` variable.
+
+```yaml
+cluster_issuer_acme_server: https://acme.example.com
+cluster_issuer_acme_email: user@example.com
+```
+
+### DNS-01 challenges
+
+Atmosphere uses the `HTTP-01` solver by default, which means that as long as
+your ACME server can reach your API, you don't need to do anything else.
+
+If your ACME server cannot reach your API, you will need to use the DNS-01
+challenges which require you to configure your DNS provider.
+
+#### RFC2136
+
+If you have DNS server that supports RFC2136, you can use it to solve the DNS
+challenges, you can use the following configuration:
+
+```yaml
+cluster_issuer_acme_email: user@example.com
+cluster_issuer_acme_solver: rfc2136
+cluster_issuer_acme_rfc2136_nameserver: <NAMESERVER>:<PORT>
+cluster_issuer_acme_rfc2136_tsig_algorithm: <ALGORITHM>
+cluster_issuer_acme_rfc2136_tsig_key_name: <KEY_NAME>
+cluster_issuer_acme_rfc2136_tsig_secret_key: <SECRET_KEY>
+```
+
+#### Route53
+
+If you are using Route53 to host the DNS for your domains, you can use the
+following configuration:
+
+```yaml
+cluster_issuer_acme_email: user@example.com
+cluster_issuer_acme_solver: route53
+cluster_issuer_acme_route53_region: <REGION>
+cluster_issuer_acme_route53_hosted_zone_id: <HOSTED_ZONE_ID>
+cluster_issuer_acme_route53_access_key_id: <AWS_ACCESS_KEY_ID>
+cluster_issuer_acme_route53_secret_access_key: <AWS_SECRET_ACCESS_KEY>
+```
+
+!!! note
+
+ You'll need to make sure that your AWS credentials have the correct
+ permissions to update the Route53 zone.
+
+## Using pre-existing CA
+
+If you have an existing CA that you'd like to use with Atmosphere, you can
+simply configure it by including the certificate and private key:
+
+```yaml
+cluster_issuer_type: ca
+cluster_issuer_ca_certificate: |
+ -----BEGIN CERTIFICATE-----
+ MIIDBjCCAe4CCQDQ3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
+ VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
+ ...
+ -----END CERTIFICATE-----
+cluster_issuer_ca_private_key: |
+ -----BEGIN RSA PRIVATE KEY-----
+ MIIEpAIBAAKCAQEAw3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
+ VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
+ ...
+ -----END RSA PRIVATE KEY-----
+```
+
+!!! note
+
+ If your issuer is an intermediate certificate, you will need to ensure that
+ they `certificate` key includes the full chain in the correct order of issuer,
+ intermediate(s) then root.
+
+## Self-signed certificates
+
+If you are in an environment which does not have a trusted certificate authority
+and it does not have access to the internet to be able to use LetsEncrypt, you
+can use self-signed certificates by adding the following to your inventory:
+
+```yaml
+cluster_issuer_type: self-signed
+```
+
+!!! warning
+
+ Self-signed certificates are not recommended for production environments,
+ they are only recommended for development and testing environments.
diff --git a/roles/cluster_issuer/defaults/main.yml b/roles/cluster_issuer/defaults/main.yml
new file mode 100644
index 0000000..b7bcfb9
--- /dev/null
+++ b/roles/cluster_issuer/defaults/main.yml
@@ -0,0 +1,53 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+cluster_issuer_name: "{{ atmosphere_ingress_cluster_issuer }}"
+cluster_issuer_type: acme
+
+cluster_issuer_acme_server: https://acme-v02.api.letsencrypt.org/directory
+# cluster_issuer_acme_email:
+cluster_issuer_acme_private_key_secret_name: cert-manager-issuer-account-key
+
+cluster_issuer_acme_solver: http01
+
+cluster_issuer_acme_http01_ingress_class: "{{ atmosphere_ingress_class_name }}"
+
+cluster_issuer_acme_rfc2136_secret_name: cert-manager-issuer-tsig-secret-key
+# cluster_issuer_acme_rfc2136_nameserver: <NAMESERVER>:<PORT>
+# cluster_issuer_acme_rfc2136_tsig_algorithm: <ALGORITHM>
+# cluster_issuer_acme_rfc2136_tsig_key_name: <KEY_NAME>
+# cluster_issuer_acme_rfc2136_tsig_secret_key: <SECRET_KEY>
+
+cluster_issuer_acme_route53_secret_name: cert-manager-issuer-route53-credentials
+# cluster_issuer_acme_route53_region: <REGION>
+# cluster_issuer_acme_route53_hosted_zone_id: <HOSTED_ZONE_ID>
+# cluster_issuer_acme_route53_access_key_id: <AWS_ACCESS_KEY_ID>
+# cluster_issuer_acme_route53_secret_access_key: <AWS_SECRET_ACCESS_KEY>
+
+cluster_issuer_ca_secret_name: cert-manager-issuer-ca
+# cluster_issuer_ca_certificate: |
+# -----BEGIN CERTIFICATE-----
+# MIIDBjCCAe4CCQDQ3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
+# VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
+# ...
+# -----END CERTIFICATE-----
+# cluster_issuer_ca_private_key: |
+# -----BEGIN RSA PRIVATE KEY-----
+# MIIEpAIBAAKCAQEAw3Z0Z2Z0Z0jANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
+# VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x
+# ...
+# -----END RSA PRIVATE KEY-----
+
+cluster_issuer_self_signed_certificate_name: self-signed-ca
+cluster_issuer_self_signed_secret_name: cert-manager-selfsigned-ca
diff --git a/roles/certificates/meta/main.yml b/roles/cluster_issuer/handlers/main.yml
similarity index 62%
copy from roles/certificates/meta/main.yml
copy to roles/cluster_issuer/handlers/main.yml
index 921f51d..711faa3 100644
--- a/roles/certificates/meta/main.yml
+++ b/roles/cluster_issuer/handlers/main.yml
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
+# Copyright (c) 2023 VEXXHOST, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -12,17 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-galaxy_info:
- author: VEXXHOST, Inc.
- description: Ansible role for distributing certificates
- license: Apache-2.0
- min_ansible_version: 5.5.0
- standalone: false
- platforms:
- - name: Ubuntu
- versions:
- - focal
-
-dependencies:
- - role: defaults
- - role: atmosphere
+- name: Update CA certificates on host
+ ansible.builtin.command:
+ cmd: update-ca-certificates
diff --git a/roles/certificates/meta/main.yml b/roles/cluster_issuer/meta/main.yml
similarity index 86%
rename from roles/certificates/meta/main.yml
rename to roles/cluster_issuer/meta/main.yml
index 921f51d..517631b 100644
--- a/roles/certificates/meta/main.yml
+++ b/roles/cluster_issuer/meta/main.yml
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
+# Copyright (c) 2023 VEXXHOST, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -14,7 +14,7 @@
galaxy_info:
author: VEXXHOST, Inc.
- description: Ansible role for distributing certificates
+ description: Ansible role for creating ClusterIssuer
license: Apache-2.0
min_ansible_version: 5.5.0
standalone: false
@@ -25,4 +25,3 @@
dependencies:
- role: defaults
- - role: atmosphere
diff --git a/roles/cluster_issuer/tasks/main.yml b/roles/cluster_issuer/tasks/main.yml
new file mode 100644
index 0000000..5416426
--- /dev/null
+++ b/roles/cluster_issuer/tasks/main.yml
@@ -0,0 +1,49 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- name: Create self-signed cluster issuer
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: cert-manager.io/v1
+ kind: ClusterIssuer
+ metadata:
+ name: self-signed
+ spec:
+ selfSigned: {}
+
+- name: Import tasks for ClusterIssuer type
+ ansible.builtin.include_tasks: "type/{{ cluster_issuer_type }}/main.yml"
+
+- name: Bootstrap PKI
+ when: cluster_issuer_type in ("self-signed", "ca")
+ block:
+ - name: Wait till the secret is created
+ kubernetes.core.k8s_info:
+ api_version: v1
+ kind: Secret
+ name: "{{ (cluster_issuer_type == 'self-signed') | ternary(cluster_issuer_self_signed_secret_name, cluster_issuer_ca_secret_name) }}"
+ namespace: cert-manager
+ wait: true
+ wait_sleep: 1
+ wait_timeout: 600
+ register: _cluster_issuer_ca_secret
+
+ - name: Copy CA certificate on host
+ ansible.builtin.copy:
+ content: "{{ _cluster_issuer_ca_secret.resources[0].data['tls.crt'] | b64decode }}"
+ dest: /usr/local/share/ca-certificates/atmosphere.crt
+ mode: 0644
+ notify:
+ - Update CA certificates on host
diff --git a/roles/certificates/meta/main.yml b/roles/cluster_issuer/tasks/type/acme/main.yml
similarity index 62%
copy from roles/certificates/meta/main.yml
copy to roles/cluster_issuer/tasks/type/acme/main.yml
index 921f51d..5adb9f8 100644
--- a/roles/certificates/meta/main.yml
+++ b/roles/cluster_issuer/tasks/type/acme/main.yml
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
+# Copyright (c) 2023 VEXXHOST, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -12,17 +12,5 @@
# License for the specific language governing permissions and limitations
# under the License.
-galaxy_info:
- author: VEXXHOST, Inc.
- description: Ansible role for distributing certificates
- license: Apache-2.0
- min_ansible_version: 5.5.0
- standalone: false
- platforms:
- - name: Ubuntu
- versions:
- - focal
-
-dependencies:
- - role: defaults
- - role: atmosphere
+- name: Import tasks for solver type
+ ansible.builtin.include_tasks: "solver/{{ cluster_issuer_acme_solver }}.yml"
diff --git a/roles/cluster_issuer/tasks/type/acme/solver/http01.yml b/roles/cluster_issuer/tasks/type/acme/solver/http01.yml
new file mode 100644
index 0000000..363dc64
--- /dev/null
+++ b/roles/cluster_issuer/tasks/type/acme/solver/http01.yml
@@ -0,0 +1,32 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- name: Create ClusterIssuer
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ apiVersion: cert-manager.io/v1
+ kind: ClusterIssuer
+ metadata:
+ name: "{{ cluster_issuer_name }}"
+ spec:
+ acme:
+ email: "{{ cluster_issuer_acme_email }}"
+ server: "{{ cluster_issuer_acme_server }}"
+ privateKeySecretRef:
+ name: "{{ cluster_issuer_acme_private_key_secret_name }}"
+ solvers:
+ - http01:
+ ingress:
+ class: "{{ cluster_issuer_acme_http01_ingress_class }}"
diff --git a/roles/cluster_issuer/tasks/type/acme/solver/rfc2136.yml b/roles/cluster_issuer/tasks/type/acme/solver/rfc2136.yml
new file mode 100644
index 0000000..60306ea
--- /dev/null
+++ b/roles/cluster_issuer/tasks/type/acme/solver/rfc2136.yml
@@ -0,0 +1,46 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- name: Create ClusterIssuer
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ - apiVersion: v1
+ kind: Secret
+ metadata:
+ name: "{{ cluster_issuer_acme_rfc2136_secret_name }}"
+ namespace: cert-manager
+ type: Opaque
+ stringData:
+ tsig-secret-key: "{{ cluster_issuer_acme_rfc2136_tsig_secret_key }}"
+
+ - apiVersion: cert-manager.io/v1
+ kind: ClusterIssuer
+ metadata:
+ name: "{{ cluster_issuer_name }}"
+ spec:
+ acme:
+ email: "{{ cluster_issuer_acme_email }}"
+ server: "{{ cluster_issuer_acme_server }}"
+ privateKeySecretRef:
+ name: "{{ cluster_issuer_acme_private_key_secret_name }}"
+ solvers:
+ - dns01:
+ rfc2136:
+ nameserver: "{{ cluster_issuer_acme_rfc2136_nameserver }}"
+ tsigAlgorithm: "{{ cluster_issuer_acme_rfc2136_tsig_algorithm }}"
+ tsigKeyName: "{{ cluster_issuer_acme_rfc2136_tsig_key_name }}"
+ tsigSecretSecretRef:
+ name: "{{ cluster_issuer_acme_rfc2136_secret_name }}"
+ key: tsig-secret-key
diff --git a/roles/cluster_issuer/tasks/type/acme/solver/route53.yml b/roles/cluster_issuer/tasks/type/acme/solver/route53.yml
new file mode 100644
index 0000000..fa805d6
--- /dev/null
+++ b/roles/cluster_issuer/tasks/type/acme/solver/route53.yml
@@ -0,0 +1,46 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- name: Create ClusterIssuer
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ - apiVersion: v1
+ kind: Secret
+ metadata:
+ name: "{{ cluster_issuer_acme_route53_secret_name }}"
+ namespace: cert-manager
+ type: Opaque
+ stringData:
+ secret-access-key: "{{ cluster_issuer_acme_route53_secret_access_key }}"
+
+ - apiVersion: cert-manager.io/v1
+ kind: ClusterIssuer
+ metadata:
+ name: "{{ cluster_issuer_name }}"
+ spec:
+ acme:
+ email: "{{ cluster_issuer_acme_email }}"
+ server: "{{ cluster_issuer_acme_server }}"
+ privateKeySecretRef:
+ name: "{{ cluster_issuer_acme_private_key_secret_name }}"
+ solvers:
+ - dns01:
+ route53:
+ region: "{{ cluster_issuer_acme_route53_region }}"
+ hostedZoneID: "{{ cluster_issuer_acme_route53_hosted_zone_id }}"
+ accessKeyID: "{{ cluster_issuer_acme_route53_access_key_id }}"
+ secretAccessKeySecretRef:
+ name: "{{ cluster_issuer_acme_route53_secret_name }}"
+ key: secret-access-key
diff --git a/roles/cluster_issuer/tasks/type/ca/main.yml b/roles/cluster_issuer/tasks/type/ca/main.yml
new file mode 100644
index 0000000..dd5394b
--- /dev/null
+++ b/roles/cluster_issuer/tasks/type/ca/main.yml
@@ -0,0 +1,35 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- name: Create ClusterIssuer
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ - apiVersion: v1
+ kind: Secret
+ metadata:
+ name: "{{ cluster_issuer_ca_secret_name }}"
+ namespace: cert-manager
+ type: kubernetes.io/tls
+ data:
+ tls.crt: "{{ cluster_issuer_ca_certificate }}"
+ tls.key: "{{ cluster_issuer_ca_private_key }}"
+
+ - apiVersion: cert-manager.io/v1
+ kind: ClusterIssuer
+ metadata:
+ name: "{{ cluster_issuer_name }}"
+ spec:
+ ca:
+ secretName: "{{ cluster_issuer_ca_secret_name }}"
diff --git a/roles/cluster_issuer/tasks/type/self-signed/main.yml b/roles/cluster_issuer/tasks/type/self-signed/main.yml
new file mode 100644
index 0000000..8461003
--- /dev/null
+++ b/roles/cluster_issuer/tasks/type/self-signed/main.yml
@@ -0,0 +1,43 @@
+# Copyright (c) 2023 VEXXHOST, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+- name: Create ClusterIssuer
+ kubernetes.core.k8s:
+ state: present
+ definition:
+ - apiVersion: cert-manager.io/v1
+ kind: Certificate
+ metadata:
+ name: "{{ cluster_issuer_self_signed_certificate_name }}"
+ namespace: cert-manager
+ spec:
+ isCA: true
+ commonName: selfsigned-ca
+ secretName: "{{ cluster_issuer_self_signed_secret_name }}"
+ duration: 87600h
+ renewBefore: 360h
+ privateKey:
+ algorithm: ECDSA
+ size: 256
+ issuerRef:
+ kind: ClusterIssuer
+ name: self-signed
+
+ - apiVersion: cert-manager.io/v1
+ kind: ClusterIssuer
+ metadata:
+ name: "{{ cluster_issuer_name }}"
+ spec:
+ ca:
+ secretName: "{{ cluster_issuer_self_signed_secret_name }}"
diff --git a/roles/openstack_cli/meta/main.yml b/roles/openstack_cli/meta/main.yml
index 3108e1f..9b0260e 100644
--- a/roles/openstack_cli/meta/main.yml
+++ b/roles/openstack_cli/meta/main.yml
@@ -25,4 +25,3 @@
dependencies:
- role: defaults
- - role: certificates
diff --git a/roles/openstacksdk/meta/main.yml b/roles/openstacksdk/meta/main.yml
index 285d65a..eb42ef3 100644
--- a/roles/openstacksdk/meta/main.yml
+++ b/roles/openstacksdk/meta/main.yml
@@ -25,4 +25,3 @@
dependencies:
- role: defaults
- - role: certificates