---
title: Certificate Request Identity
authors:
  - "@joshvanl"
reviewers:
  - "@joshvanl"
approvers:
  - "@joshvanl"
editor: "@joshvanl"
creation-date: 2021-02-03
last-updated: 2021-02-03
status: implemented
---

# Identity

## Table of Contents

<!-- toc -->
- [Summary](#summary)
- [Motivation](#motivation)
  - [Goals](#goals)
  - [Non-Goals](#non-goals)
- [Proposal](#proposal)
  - [API Changes](#api-changes)
  - [Upgrading](#upgrading)
  - [Test Plan](#test-plan)
  - [Risks and Mitigations](#risks-and-mitigations)
  - [Certificate Identity Pass Down](#certificate-identity-pass-down)
<!-- /toc -->

## Summary

In order to implement policy and improve auditing introspection of certificates
requested and signed by cert-manager, cert-manager must implement a better
identity framework. Identity in this context is a user or machine which requests
a signed certificate from cert-manager. This identity will be managed and
enforced on CertificateRequest resources by cert-manager.


## Motivation

The identity of a requester forms a large part of an automated policy system
that needs to decide whether a certificate should or shouldn't be signed. By
creating a trusted source of identity for `CertificateRequest`s, a policy engine
is able to determine whether that identity is allowed to request that
certificate, given some policy configuration setup by a cluster administrator.

Although auditing exists in Kubernetes and exposes the identity of the
requester, its configuration is not always exposed to end users, such as
when using managed Kubernetes (GKE, EKS etc). In scenarios where
configuring auditing is available, it is often not preferable and an
anti-pattern to make runtime decisions on historical audit logs.

The upstream [Kubernetes certificates
`CertificateSigningRequest`](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#certificatesigningrequest-v1-certificates-k8s-io)
API has the identity of the requesting Kubernetes user. As the project intends
to transition to this resource as part of the project, the `CertificateRequest`
should strive to match 1:1 wherever possible. This means extensions or additions
to cert-manager (policy, auditing) can have the same guarantees about what
information is available from both resources, while this transition takes place.


### Goals

- Introduce identity to the `CertificateRequest` resource which is securely
    enforced by cert-manager
- Ensure the identity exposed in `CertificateRequest`s has parity with the
    upstream Kubernetes `CertificateSigningRequest` resource
- Enable external tooling or additions to cert-manager that can make use of this
    identity in a useful way

### Non-Goals

- Dictate any kind of means through which identity or policy evaluation should
  be performed (rather, only the building blocks to enable others to build
  evaluation systems is a goal)
- Make changes to upstream Kubernetes to implement identity in cert-manager
- Although considered below, ["passed down"](#certificate-identity-pass-down)
  identity is not part of this design

## Proposal

Kubernetes does [not currently support immutable
fields](https://github.com/kubernetes/enhancements/blob/8b9b994136371f1bc938aabf012f4c45535d684c/keps/sig-api-machinery/20190603-immutable-fields.md)
for CRDs. The cert-manager webhook will be responsible for populating and
enforcing user info fields which are present on the spec of `CertificateRequest`
resources.

The webhook will be responsible for enforcing the following during a CREATE
operation. We will not reject requests which populate these fields, but instead
simply override them.
- No user info fields have been set by the [user creating the resource](
  https://github.com/kubernetes/kubernetes/blob/7a94debba5f8c21bbf8b42b2a7f1d5e974ddb837/pkg/registry/certificates/certificates/strategy.go#L63-L79)
- Set user info fields to exactly what is received from the API server in the
    [UserInfo](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#userinfo-v1-authentication-k8s-io)

The webhook will also responsible for enforcing the following during an UPDATE
operation. Any attempt to changes these fields will result in a rejected
request.
- No changes to user info fields are allowed to be made

### API Changes

In order to expose the user info of who created `CertificateRequest` resources,
these resources must be updated to have parity with the upstream Kubernetes
certificates API.
This means that the `CertificateRequest` API type be updated to include the
following fields in spec, for all API versions:

```go
type CertificateRequestSpec {
  // EXISTING FIELDS
  // ...

  // NEW FIELDS

	// Username contains the name of the user that created the CertificateRequest.
	// Populated by the cert-manager webhook on creation and immutable.
	// +optional
	Username string `json:"username,omitempty"`
	// UID contains the uid of the user that created the CertificateRequest.
	// Populated by the cert-manager webhook on creation and immutable.
	// +optional
	UID string `json:"uid,omitempty"`
	// Groups contains group membership of the user that created the CertificateRequest.
	// Populated by the cert-manager webhook on creation and immutable.
	// +listType=atomic
	// +optional
	Groups []string `json:"groups,omitempty"`
	// Extra contains extra attributes of the user that created the CertificateRequest.
	// Populated by the cert-manager webhook on creation and immutable.
	// +optional
	Extra map[string][]string `json:"extra,omitempty"`
```

All new fields here are marked as optional. It is likely for a number of them to
be empty for a given request, depending on the requester's identity. It is up to
any component consuming the user info fields to make appropriate decisions about
fields which are not populated.

### Upgrading

Any `CertificateRequest`s that are present in the cluster at the time of
upgrade, won't and will never have their user info fields populated. This should
be acceptable.

All subsequent `CertificateRequest`s created after this upgrade will have their
identities populated.

When the CRDs are upgraded, there will be a brief period where the user info
fields will not be populated until the webhook is also upgraded.

### Test Plan

Unit tests will be created is ensure that the [properties](#proposal) are
enforced.

End to end tests will ensure that different users creating `CertificateRequest`
resources have their respective identities populated in the fields.

### Risks and Mitigations

There are large security implications if the user info fields that other
components rely on are wrong, or could be made fraudulent. Special care when
testing needs to be given to ensure the properties described above are correct
and enforced.

If the validating or mutating webhooks were not installed properly, either by
being out of date or deleted, then this would invalidate the security guarantees
of the user info fields.

### Certificate Identity Pass Down

`CertificateRequest`s created and managed via `Certificate` resources will have
the user info of the cert-manager controller. Though this design doesn't provide
a solution to components that need to traverse the user info to the original
user who created the `Certificate` resource, some possible further design
options are;
- cert-manager would override the user info fields with the of the identity that
    created the `Certificate` resource, if cert-manager is the creator.
- Consumers of the identity will need to be aware that the `CertificateRequest`
    may be managed by a `Certificate` resource if it is created by cert-manager,
    and should look at the identity of the `Certificate`.
- cert-manager manages some signing key pair and populates the annotation of
    the `CertificateRequest` with a JWT containing the original identity.
    Consumers can then validate that JWT using a distributed public key, and
    make use of the identity it contains.
