Approve a CSR in Kuberentes Using the Python client

3/15/2019

I have the following CSR object in Kubernetes:

$ kubectl get csr
NAME                                     AGE       REQUESTOR                                      CONDITION
test-certificate-0.my-namespace          53m       system:serviceaccount:my-namespace:some-user   Pending

And I would like to approve it using the Python API client:

from kuberentes import config, client
# configure session
config.load_kube_config()
# get a hold of the certs API
certs_api = client.CertificatesV1beta1Api()

# read my CSR
csr = certs_api.read_certificate_signing_request("test-certificate-0.my-namespace")

Now, the contents of the csr object are:

{'api_version': 'certificates.k8s.io/v1beta1',
 'kind': 'CertificateSigningRequest',
 'metadata': {'annotations': None,
              'cluster_name': None,
              'creation_timestamp': datetime.datetime(2019, 3, 15, 14, 36, 28, tzinfo=tzutc()),
              'deletion_grace_period_seconds': None,
              'name': 'test-certificate-0.my-namespace',
              'namespace': None,
              'owner_references': None,
              'resource_version': '4269575',
              'self_link': '/apis/certificates.k8s.io/v1beta1/certificatesigningrequests/test-certificate-0.my-namespace',
              'uid': 'b818fa4e-472f-11e9-a394-124b379b4e12'},
 'spec': {'extra': None,
          'groups': ['system:serviceaccounts',
                     'system:serviceaccounts:cloudp-38483-test01',
                     'system:authenticated'],
          'request': 'redacted',
          'uid': 'd5bfde1b-4036-11e9-a394-124b379b4e12',
          'usages': ['digital signature', 'key encipherment', 'server auth'],
          'username': 'system:serviceaccount:test-certificate-0.my-namespace'},
 'status': {'certificate': 'redacted',
            'conditions': [{'last_update_time': datetime.datetime(2019, 3, 15, 15, 13, 32, tzinfo=tzutc()),
                            'message': 'This CSR was approved by kubectl certificate approve.',
                            'reason': 'KubectlApprove',
                            'type': 'Approved'}]}}

I would like to approve this cert programmatically, if I use kubectl to do it with (-v=10 will make kubectl output the http trafffic):

kubectl certificate approve test-certificate-0.my-namespace -v=10

I get to see the PUT operation used to Approve my certificate:

PUT https://my-kubernetes-cluster.com:8443/apis/certificates.k8s.io/v1beta1/certificatesigningrequests/test-certificate-0.my-namespace/approval

So I need to PUT to the /approval resource of the certificate object. Now, how do I do it with the Python Kubernetes client?

-- licorna
kubernetes
kubernetes-python-client
python

2 Answers

3/15/2019

It's got a weird name, but it's in the docs for the python client - you want replace_certificate_signing_request_approval

# create an instance of the API class
api_instance = kubernetes.client.CertificatesV1beta1Api(kubernetes.client.ApiClient(configuration))
name = 'name_example' # str | name of the CertificateSigningRequest
body = kubernetes.client.V1beta1CertificateSigningRequest() # V1beta1CertificateSigningRequest | 
dry_run = 'dry_run_example' # str | When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed (optional)
pretty = 'pretty_example' # str | If 'true', then the output is pretty printed. (optional)

try: 
    api_response = api_instance.replace_certificate_signing_request_approval(name, body, dry_run=dry_run, pretty=pretty)
    pprint(api_response)
except ApiException as e:
    print("Exception when calling CertificatesV1beta1Api->replace_certificate_signing_request_approval: %s\n" % e)
-- jaxxstorm
Source: StackOverflow

3/20/2019

Here's to answer my question based on @jaxxstorm answer and my own investigation:

# Import required libs and configure your client
from datetime import datetime, timezone
from kubernetes import config, client
config.load_kube_config()

# this is the name of the CSR we want to Approve
name = 'my-csr'

# a reference to the API we'll use 
certs_api = client.CertificatesV1beta1Api()

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

# create an approval condition
approval_condition = client.V1beta1CertificateSigningRequestCondition(
    last_update_time=datetime.now(timezone.utc).astimezone(),
    message='This certificate was approved by Python Client API',
    reason='MyOwnReason',
    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(name, body)

After this, the KubeCA will approve and issue the new certificate. The issued certificate file can be obtained from the response object we just got:

import base64
base64.b64decode(response.status.certificate) # this will return the decoded cert
-- licorna
Source: StackOverflow