def get_resource_api(api_client: client.ApiClient = None,
                      **kwargs) -> "client.CertificatesV1beta1Api":
     """
     Returns an instance of the kubernetes API client associated with
     this object.
     """
     if api_client:
         kwargs["apl_client"] = api_client
     return client.CertificatesV1beta1Api(**kwargs)
示例#2
0
def confirm_certificate_signing_request(context):
    if context is None:
        raise SystemExit(
            "invalid empty context for CertificateSigningRequest given")
    load_kube(context)
    api = client.CertificatesV1beta1Api()
    return general_confirm("CertificateSigningRequest",
                           lambda: api.list_certificate_signing_request(),
                           lambda i: i.metadata.name)
示例#3
0
def wait_for_certificate_signing_request_is_away(context, name):
    if name is None:
        raise SystemExit(
            "invalid empty name for CertificateSigningRequest given")
    if context is None:
        raise SystemExit("invalid empty name context given")
    load_kube(context)
    print("check removal of", "CertificateSigningRequest", name)
    api = client.CertificatesV1beta1Api()
    return general_away_check(
        None, "CertificateSigningRequest", name,
        lambda: api.read_certificate_signing_request_with_http_info(name))
示例#4
0
def remove_certificate_signing_request(context, name):
    if context is None:
        raise SystemExit(
            "invalid empty context for CertificateSigningRequest given")
    if name is None:
        raise SystemExit(
            "invalid empty name for CertificateSigningRequest given")

    load_kube(context)
    api = client.CertificatesV1beta1Api()
    ret, status, _ = api.delete_certificate_signing_request_with_http_info(
        name)
    handle_status(ret, status, "CertificateSigningRequest", None, name)
示例#5
0
def run_csr_approval(client: k8s.ApiClient,
                     node_csr_spec: Dict[str, Any]) -> None:
    api = k8s.CertificatesV1beta1Api(client)
    csrs: k8s.V1beta1CertificateSigningRequestList \
        = api.list_certificate_signing_request()
    now = datetime.utcnow()
    csrs_to_approve = iterate_csrs(csrs, node_csr_spec)
    for csr in csrs_to_approve:
        try:
            create_approval_patch(csr, now)
            api.replace_certificate_signing_request_approval(
                csr.metadata.name, body=csr)
        except BaseException as e:
            # Log, but don't quit -> continue processing other CSRs
            logger.error(e, exc_info=True)
def valiate_approve_csr(csrList, nodeInfoList):

    # Initialize empty lists
    (
        approvedBootStrappedNodes,
        approvedNodes,
        approvedNodesToLabel,
        approvedCSRs,
        approvedNodesToTaint,
    ) = ([], [], [], [], [])

    # a reference to the API
    certs_api = client.CertificatesV1beta1Api()

    # Auth user and groups
    bootstrapGroups = [
        "system:serviceaccounts:openshift-machine-config-operator",
        "system:authenticated",
        "system:serviceaccounts",
    ]
    bootstrapUser = (
        "system:serviceaccount:openshift-machine-config-operator:node-bootstrapper"
    )

    nodeGroups = ["system:nodes", "system:authenticated"]
    nodeUser = "******"

    for csrName in csrList:

        # Initialize variables
        csrType, dnsName, ip = None, None, None

        nodeUserValidation = False
        bootstrapUserValidation = False

        # obtain the body of the CSR we want to sign
        body = certs_api.read_certificate_signing_request_status(csrName)

        # Decode base64 string to pem format csr
        decodedCertificate = base64.b64decode(
            body.spec.request).decode("utf-8")

        # Load pem format csr
        try:
            certificate = cryptography.x509.load_pem_x509_csr(
                bytes(decodedCertificate, encoding="utf8"), default_backend())
        except Exception:
            print("Error loading CSR")
            sys.exit(1)

        if ("bootstrapper" in body.spec.username
                and "system:node:" not in body.spec.username):

            groupDifference = set(bootstrapGroups) - set(body.spec.groups)
            dnsName = certificate.subject.get_attributes_for_oid(
                cryptography.x509.oid.NameOID.COMMON_NAME)[0].value.split(
                    ":")[2]

            if (dnsName and body.spec.username == bootstrapUser
                    and len(groupDifference) == 0):

                csrType = "bootstrapper"
                bootstrapUserValidation = True

        elif ("bootstrapper" not in body.spec.username
              and "system:node:" in body.spec.username):

            groupDifference = set(nodeGroups) - set(body.spec.groups)

            crt_san_data = certificate.extensions.get_extension_for_oid(
                cryptography.x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
            dnsName = crt_san_data.value.get_values_for_type(
                cryptography.x509.DNSName)[0]
            ip = crt_san_data.value.get_values_for_type(
                cryptography.x509.IPAddress)[0]

            if (dnsName and body.spec.username == nodeUser + dnsName
                    and len(groupDifference) == 0):

                csrType = "node"
                nodeUserValidation = True

        else:
            print("Unknown CSR type")
            sys.exit(1)

        if (csrType == "node" and next(
            (item for item in nodeInfoList if item["node"] == dnsName), None)
                and next(
                    (item
                     for item in nodeInfoList if item["ip"] == str(ip)), None)
                and nodeUserValidation) or (csrType == "bootstrapper" and next(
                    (item for item in nodeInfoList if item["node"] == dnsName),
                    None) and bootstrapUserValidation):

            # create an approval condition
            approval_condition = client.V1beta1CertificateSigningRequestCondition(
                last_update_time=datetime.now(timezone.utc).astimezone(),
                message=
                "This certificate was approved by CSR Approval Operator",
                reason="Validated and approved by CSR Approval Operator",
                type="Approved",
            )

            # patch the existing `body` with the new conditions
            # you might want to append the new conditions to the existing ones
            body.status.conditions = [approval_condition]

            # patch the Kubernetes object
            response = certs_api.replace_certificate_signing_request_approval(
                csrName, body)

            # Increase count of approvedCSRCount variable
            approvedCSRs.append(csrName)

            if csrType == "node" and any("label" in d for d in nodeInfoList
                                         if d["node"] == dnsName):
                approvedNodesToLabel.append({
                    "node":
                    dnsName,
                    "label":
                    "".join([
                        d["label"] for d in nodeInfoList
                        if d["node"] == dnsName
                    ]),
                })
                approvedNodes.append(dnsName)

            if csrType == "node" and any("taint" in d for d in nodeInfoList
                                         if d["node"] == dnsName):
                approvedNodesToTaint.append({
                    "node":
                    dnsName,
                    "taint":
                    "".join([
                        d["taint"] for d in nodeInfoList
                        if d["node"] == dnsName
                    ]),
                })
                approvedNodes.append(dnsName)

            if csrType == "node" and not any("label" in d for d in nodeInfoList
                                             if d["node"] == dnsName):
                approvedNodes.append(dnsName)

            if csrType == "bootstrapper":
                approvedBootStrappedNodes.append(dnsName)

            approvedNodes = list(dict.fromkeys(approvedNodes))

    return (
        approvedNodes,
        approvedCSRs,
        approvedNodesToLabel,
        approvedBootStrappedNodes,
        approvedNodesToTaint,
    )
示例#7
0
def init_tls_pair(namespace):
    """Function to load or create tls for admission webhook"""

    tls_pair = ""

    logging.info("Starting TLS init process")

    # Check if custom secret was specified in ENV vars
    magtape_tls_secret_name = os.getenv("magtape_tls_secret_name",
                                        magtape_tls_pair_secret_name)

    if magtape_tls_secret_name != magtape_tls_pair_secret_name:

        logging.debug("Magtape TLS Secret specified")

    try:

        config.load_incluster_config()

    except Exception as exception:

        logging.info(
            f"Exception loading in-cluster configuration: {exception}")

        try:
            logging.info("Loading local kubeconfig")
            config.load_kube_config()

        except Exception as exception:

            logging.error(f"Exception loading local kubeconfig: {exception}")
            sys.exit(1)

    configuration = client.Configuration()
    core_api = client.CoreV1Api(client.ApiClient(configuration))
    certificates_api = client.CertificatesV1beta1Api(
        client.ApiClient(configuration))

    # Read existing secret
    tls_secret, tls_pair, secret_exists, magtape_tls_byoc = read_tls_pair(
        namespace, magtape_tls_pair_secret_name, tls_pair, core_api)

    if secret_exists:

        logging.info("Existing TLS cert and key found")

    # Check if cert should be updated
    secret_should_update = cert_should_update(namespace, secret_exists,
                                              tls_secret, magtape_tls_byoc)

    if secret_should_update:

        if magtape_tls_byoc:

            logging.warning(
                f"WARN - Certificate used for Admission Webhook is past threshhold for normal rotation. Not rotating because this cert isn't managed by the K8s CA"
            )

        else:

            logging.info(f"Generating new cert/key pair for TLS")

            # Generate TLS Pair
            tls_pair = build_tls_pair(
                namespace,
                magtape_tls_pair_secret_name,
                magtape_service_name,
                certificates_api,
            )

    # Handle cert creation or update
    write_tls_pair(
        namespace,
        magtape_tls_secret_name,
        secret_exists,
        secret_should_update,
        tls_secret,
        tls_pair,
        magtape_tls_byoc,
        core_api,
    )
示例#8
0
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

formatter = TextFormatter(datefmt="Z", colorize=True)

ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)

config.load_kube_config()

corev1_api = client.CoreV1Api(client.ApiClient())
apps_v1_api = client.AppsV1Api(client.ApiClient())
webhook_api = client.AdmissionregistrationV1beta1Api(client.ApiClient())
cert_api = client.CertificatesV1beta1Api(client.ApiClient())

APP_NAME = "maglev-admission-webhook"
SECRET = "shhhh!donottell"
NAMESPACE = "default"
CSR_NAME = "{}.{}".format(APP_NAME, NAMESPACE)
IMAGE = "harshanarayana/sanic-webhook:v0.2"

TEMPLATE_ENV = Environment(loader=BaseLoader)
RESOURCE_CREATION_MAP = {
    "Deployment": {
        "handler": apps_v1_api.create_namespaced_deployment
    },
    "Service": {
        "handler": corev1_api.create_namespaced_service
    },
 def __init__(self):
     self.core = client.CoreV1Api()
     self.certs = client.CertificatesV1beta1Api()
     self.rbac = client.RbacAuthorizationV1Api()
     self.settings_api = client.SettingsV1alpha1Api()
     self.policy = client.PolicyV1beta1Api()
示例#10
0
from OpenSSL.crypto import FILETYPE_PEM, load_certificate_request
import yaml
from kubernetes import client, config, watch
import os
import re

if __name__ == "__main__":
    if 'KUBERNETES_PORT' in os.environ:
        config.load_incluster_config()
    else:
        config.load_kube_config()
    configuration = client.Configuration()
    configuration.assert_hostname = False
    api_client = client.api_client.ApiClient(configuration=configuration)
    v1 = client.CoreV1Api()
    certs_api = client.CertificatesV1beta1Api()
    try:
        k8sfile = '/var/run/secrets/kubernetes.io/serviceaccount/namespace'
        namespace = open(k8sfile, 'r').read() if os.path.exists(
            k8sfile) else os.environ.get('NAMESPACE', 'default')
        config_map_name = os.environ.get('CONFIG_MAP', 'autorules')
        config_map = v1.read_namespaced_config_map(namespace=namespace,
                                                   name=config_map_name)
        config_map_data = config_map.to_dict().get('data', {})
    except Exception as e:
        if e.status == 404:
            print("Missing configmap %s in namespace %s" %
                  (config_map_name, namespace))
            config_map_data = {}
        else:
            print(e)
示例#11
0
                    "Certificate {} was approved.".format(metadata_name))
            except ApiException as e:
                logger.warning(
                    "Exception when calling Certificatesapi_clientbeta1Api->replace_certificate_signing_request_approval: %s\n"
                    % e)
    else:
        logger.info(
            "Certificate was already approved {}".format(metadata_name))


if __name__ == "__main__":
    if 'CLUSTER' in os.environ:
        config.load_incluster_config()
    else:
        config.load_kube_config()
    api_client = client.CertificatesV1beta1Api()
    w = watch.Watch()
    for event in w.stream(api_client.list_certificate_signing_request,
                          watch=True):
        if event["type"] not in "DELETED":
            certificate = event["object"]
            try:
                metadata_name = event["object"].metadata.name
                spec_groups = event["object"].spec.groups
                spec_username = event["object"].spec.username
                logger.info("Handling {} on {}".format(event["type"],
                                                       metadata_name))
                approve_certificate(api_client, certificate, spec_username,
                                    spec_groups, metadata_name)
            except:
                logger.warning("{} Can't handle certificate".format(