Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do you approve the CA in the cluster #47

Open
haykharut opened this issue Dec 7, 2022 · 1 comment
Open

How do you approve the CA in the cluster #47

haykharut opened this issue Dec 7, 2022 · 1 comment

Comments

@haykharut
Copy link

haykharut commented Dec 7, 2022

Hi!

I have been trying to replicate your code in Python and have reached a point where I managed to :

  1. create the certificates and a private key
  2. create the webhookconfiguration in the cluster

The problem I have is that the certificate is not recognized:

failed to call webhook: Post "...svc:443/mutate?timeout=10s": x509: certificate signed by unknown authority

Looking at your code, I cannot find how the self-signed certificate is made recognizable to kubernetes. I can see that :

There are 2 CA configs in the script and 2 certificates made. The first is passed to the webhook configuration and the second is used in the webserver together with the private key. I do not quite understand why this is enough for kubernetes to recognize the certificate signer. Isn't there supposed to be a Certificate Signing Request made?

@haykharut
Copy link
Author

For reference:

Here is my script that makes the cert + key:

import datetime

from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID


def generate_cert(org, dns_names, common_name):
    # Init CA config
    ca = (
        x509.CertificateBuilder(
            issuer_name=x509.Name(
                [x509.NameAttribute(x509.oid.NameOID.ORGANIZATION_NAME, org)]
            ),
            subject_name=x509.Name(
                [x509.NameAttribute(x509.oid.NameOID.ORGANIZATION_NAME, org)]
            ),
            serial_number=2022,
            not_valid_before=datetime.datetime.utcnow(),
            not_valid_after=datetime.datetime.utcnow() + datetime.timedelta(days=365),
            public_key=rsa.generate_private_key(
                public_exponent=65537, key_size=4096
            ).public_key(),
        )
        .add_extension(
            x509.BasicConstraints(ca=True, path_length=None),
            critical=True,
        )
        .add_extension(
            x509.KeyUsage(
                digital_signature=True,
                content_commitment=False,
                key_encipherment=False,
                data_encipherment=False,
                key_agreement=False,
                key_cert_sign=True,
                crl_sign=False,
                encipher_only=False,
                decipher_only=False,
            ),
            critical=True,
        )
        .add_extension(
            x509.ExtendedKeyUsage(
                [
                    x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH,
                    x509.oid.ExtendedKeyUsageOID.SERVER_AUTH,
                ]
            ),
            critical=False,
        )
    )
    
    # Sign CA and generate public key in PEM format
    ca_pem = ca.sign(
            private_key=rsa.generate_private_key(
                public_exponent=65537,
                key_size=4096,
            ),
            algorithm=hashes.SHA256(),
        ).public_bytes(encoding=serialization.Encoding.PEM)

    # generate new private key
    new_private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=4096,
    )

    # New certificate config
    new_cert = x509.CertificateBuilder(
        serial_number=2022,
        issuer_name=x509.Name(
            [
                x509.NameAttribute(NameOID.COMMON_NAME, common_name),
                x509.NameAttribute(NameOID.ORGANIZATION_NAME, org),
            ]
        ),
        subject_name=x509.Name(
            [
                x509.NameAttribute(NameOID.COMMON_NAME, common_name),
                x509.NameAttribute(NameOID.ORGANIZATION_NAME, org),
            ]
        ),
        not_valid_before=datetime.datetime.utcnow(),
        not_valid_after=datetime.datetime.utcnow() + datetime.timedelta(days=365),
        public_key=new_private_key.public_key(),
    )
    new_cert = new_cert.add_extension(
        x509.SubjectAlternativeName([x509.DNSName(dns_name) for dns_name in dns_names]),
        critical=False,
    )
    new_cert = new_cert.add_extension(
        x509.KeyUsage(
            digital_signature=True,
            key_encipherment=False,
            content_commitment=False,
            key_agreement=False,
            data_encipherment=False,
            key_cert_sign=True,
            crl_sign=False,
            encipher_only=False,
            decipher_only=False,
        ),
        critical=True,
    )

    # sign the new certificate and encode to PEM
    new_cert_pem = new_cert.sign(
        private_key=new_private_key,
        algorithm=hashes.SHA256(),
        backend=default_backend(),
    ).public_bytes(serialization.Encoding.PEM)

    # new private key PEM encoded
    new_private_key_pem = new_private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    )

    return ca_pem, new_cert_pem, new_private_key_pem

And here is where my webhook config

def create_or_update_mutating_webhook_configuration(
    ca_pem, webhook_service, webhook_namespace
):
    # Initialize the kube client
    clientset = client.ApiClient(config.load_incluster_config())
    # Create or update the mutatingwebhookconfiguration
    apiclient = AdmissionregistrationV1Api(api_client=clientset)

    mutating_webhook_config = client.V1MutatingWebhookConfiguration(
        metadata=client.V1ObjectMeta(name=webhook_config_name),
        webhooks=[
            client.V1MutatingWebhook(
                name="mywebhook",
                admission_review_versions=["v1", "v1beta1"],
                side_effects="None",
                client_config=client.AdmissionregistrationV1WebhookClientConfig(
                    ca_bundle=ca_pem,  # self-generated CA for the webhook
                    service=client.AdmissionregistrationV1ServiceReference(
                        name=webhook_service,
                        namespace=webhook_namespace,
                        path="/mutate",
                    ),
                ),
                rules=[
                    client.V1RuleWithOperations(
                        operations=["CREATE", "UPDATE"],
                        api_groups=[""],
                        api_versions=["v1"],
                        resources=["pods"],
                    ),
                ],
                failure_policy="Fail",
            )
        ],
    )
    ```

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant