diff --git a/design/proposals/namespace_label_authenticator.md b/design/proposals/namespace_label_authenticator.md
index 82660aaf99..a7e8517d55 100644
--- a/design/proposals/namespace_label_authenticator.md
+++ b/design/proposals/namespace_label_authenticator.md
@@ -1,4 +1,4 @@
-# Solution Design - Namespace Label Selector for the Kubernetes Authenticator
+# Solution Design - Namespace Label Identity Scope for the Kubernetes Authenticator
[//]: # "Change the title above from 'Template' to your design's title"
[//]: # "General notes:"
@@ -10,7 +10,7 @@
## Table of Contents
[//]: # "You can use this tool to generate a TOC - https://ecotrust-canada.github.io/markdown-toc/"
-- [Solution Design - Namespace Label Selector for the Kubernetes Authenticator](#solution-design---namespace-label-selector-for-the-kubernetes-authenticator)
+- [Solution Design - Namespace-Label Identity Scope for the Kubernetes Authenticator](#solution-design---namespace-label-identity-scope-for-the-kubernetes-authenticator)
* [Table of Contents](#table-of-contents)
* [Glossary](#glossary)
* [Useful Links](#useful-links)
@@ -32,9 +32,9 @@
* [Backwards Compatibility](#backwards-compatibility)
* [Affected Components](#affected-components)
* [Work in Parallel](#work-in-parallel)
+ + [Development Tasks](#development-tasks)
* [Test Plan](#test-plan)
+ [Test Environments](#test-environments)
- + [Prerequisites](#prerequisites)
+ [Test Cases (Including Performance)](#test-cases--including-performance-)
- [Functional Tests](#functional-tests)
- [Security Tests](#security-tests)
@@ -49,6 +49,7 @@
Table of contents generated with markdown-toc
+
## Glossary
[//]: # "Describe terms that will be used throughout the design"
[//]: # "You can use this tool to generate a table - https://www.tablesgenerator.com/markdown_tables#"
@@ -65,7 +66,8 @@
|-------------|----------|
| Feature Doc | |
| Issue | |
-| POC branch | https://github.com/cyberark/conjur/compare/master...authn-k8s-label-selector |
+| Kubernetes Docs: Labels and Selectors | https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ |
+| Proof-of-Concept branch | https://github.com/cyberark/conjur/compare/master...authn-k8s-label-selector |
## Background
[//]: # "Give relevant background for the designed feature. What is the motivation for this solution?"
@@ -184,42 +186,20 @@ The minimum subset of label selector flavors we need to support are
an identity to scope to a single group of similarly-labeled namespaces.
Should this feature also support:
-- **Multiple** positive equality-based selectors?
-
- **Nice to have, but not required.** Multiple equality-based selectors can be
- used to reduce scope from a single equality-based selector. An identity could
- authenticate workloads in a subset of namespaces in a single group based on
- additional labels.
-
-- **Negative** selectors (`!=`, `notin`, and `!`)?
-
- **No.** This feature should not support negative selectors, which would serve as a
- denylist in this context. Theoretically, new workloads would be able to
- authenticate by default, unless they reside in a denylisted namespace. An
- identity's scope should be meaningfully curated, not open-ended.
-
-- Positive **set-based** selectors (`in`)?
-
- **No.** Set-based selectors can be used to increase scope from a single equality-based
- selector. Support for this selector flavor would imply that a single host
- identity could authenticate on behalf of any number of namespace groups. This
- runs counter to having intentionally-scoped host identities - if two workloads
- are in separate namespaces, and those namespaces are designated to different
- sets, they should authenticate with separate identities.
-
-- Positive **existence-based** selectors?
-
- **No.** Existence based selectors filter results based on label keys, and does no
- validation on label values. While this could technically be leveraged to mimic
- positive equality-based selectors by using unique label keys, this would mean
- thoroughly polluting the label namespace.
-
-Under the hood, Kubernetes' native label selector implementation lists all
-namespaces in a given cluster, then reduces the result scope to only those that
-satisfy the condition. Using this implementation with the Kubernetes
-Authenticator requires permitting its identity to `list` all namespaces in the
-target cluster. This operation could be negatively affected if the target
-cluster is host to so many namespaces that the query operation becomes costly.
+| **Selector Type** | **Support?** | **Comments** |
+|-------------------|--------------|--------------|
+| **Multiple** positive equality-based selectors | **Nice to have, but not required** | Multiple equality-based selectors can be used to reduce scope from a single equality-based selector. An identity could authenticate workloads in a subset of namespaces in a single group based on additional labels. |
+| **Negative** selectors (`!=`, `notin`, and `!`) | **No** | This feature should not support negative selectors, which would serve as a denylist in this context. Theoretically, new workloads would be able to authenticate by default, unless they reside in a denylisted namespace. An identity's scope should be meaningfully curated, not open-ended. |
+| Positive **set-based** selectors (`in`) | **No** | Set-based selectors can be used to increase scope from a single equality-based selector. Support for this selector flavor would imply that a single host identity could authenticate on behalf of any number of namespace groups. This runs counter to having intentionally-scoped host identities - if two workloads are in separate namespaces, and those namespaces are designated to different sets, they should authenticate with separate identities. |
+| Positive **existence-based** selectors | **No** | Existence based selectors filter results based on label keys, and does no validation on label values. While this could technically be leveraged to mimic positive equality-based selectors by using unique label keys, this would mean thoroughly polluting the label namespace. |
+
+In Kubernetes, label selectors can only be applied to functions that list
+instances of a resource type - for example, a client can query a list of
+namespaces in a cluster, but limit the results to only those namespaces that
+match a given selector. Using label selectors with the Kubernetes Authenticator
+will require permitting its identity to `list` all namespaces in the target
+cluster. This operation could be negatively affected if the target cluster is
+host to so many namespaces that the list operation becomes costly.
```rb
# Retrieves all namespaces in the cluster, enforcing field selection based on
@@ -265,7 +245,7 @@ example:
- !host
id: test-app
annotations:
- authn-k8s/namespace-label-selector: "conjur.org/authn-k8s-project=dev"
+ authn-k8s/namespace-label: "conjur.org/authn-k8s-project=dev"
authn-k8s/service-account: "test-app-sa"
```
@@ -311,7 +291,7 @@ policy. All other factors in Authenticator setup are unchanged.
- !host
id: test-app
annotations:
- authn-k8s/namespace-label-selector: "key1=value1"
+ authn-k8s/namespace-label: "key1=value1"
```
Rancher creates a unique ID for Projects at creation. This ID needs to inform
@@ -341,7 +321,7 @@ This value then informs host configuration:
- !host
id: test-app
annotations:
- authn-k8s/namespace-label-selector: "field.cattle.io/projectId=${PROJECT_ID}"
+ authn-k8s/namespace-label: "field.cattle.io/projectId=${PROJECT_ID}"
```
## Design
@@ -391,28 +371,43 @@ following modules:
### Development Tasks
-- Implement and test a new Constraint, where exactly one of many restrictions is
- required.
-- Use the new Constraint to add a resource restriction to an AuthnK8s host,
- where exactly one of either `namespace` or `namespace-label-selector` is
- required.
-- Implement namespace retrieval and label parsing to validate the new
- restriction.
-- Test the public interface with in-process K8s API mock: hosts configured with
- the new restriction, when authenticating from a properly labeled namespace,
- should be authenticated.
+- [ ] Community and Integrations team ramp-up: current Kubernetes Authenticator
+ behavior, new Authn-K8s and existing project testing strategies, solution
+ details.
+- [ ] Given the name of a namespace, retrieve its labels from the K8s API server.
+- [ ] Given a map of a namespace's labels and a desired label selector, validate
+ that the label map adheres to the selector.
+- [ ] Create and test a new `Authentication::Constraint` class that can enforce
+ logical XOR on two or more resource restrictions.
+- [ ] Update Authn-K8s request validation logic to use the new `Constraint`
+ class to validate a request's origin namespace against a desired label.
+- [ ] Test the new Authn-K8s request validation end-to-end, using either a mock
+ K8s API server or live infrastructure.
+- [ ] [Spike]: How should we suggest customers secure their labels?
+- [ ] Perform final security review.
+- [ ] Assist TW with updating Kubernetes Authenticator documentation. This
+ should include:
+ 1. Updates to the Kubernetes/OpenShift integration documentation. This should
+ include only general language about using labels to group namespaces and
+ assign identity scope.
+ 2. Updates to the Rancher integration documentation. This can include
+ Rancher-specific language regarding scoping identities to Projects.
+- [ ] Perform UX review by manually following the new documentation. This will
+ include creating a label-scoped identity, creating a labeled namespace,
+ and authenticating a workload using labels.
## Test Plan
### Test Environments
[//]: # "Including build number, platforms etc. Considering the OS and version of PAS (PVWA, CPM), Conjur, Synchronizer etc."
-| **Feature** | **OS** | **Version Number** |
-|-------------|--------|--------------------|
-| | | |
+End-to-end tests should be run against resources deployed in full-fledged
+Kubernetes environments, to best replicate the typical user experience.
-### Prerequisites
-[//]: # "List any expected infrastructure requirements here"
+| **Platform** | **Versions** |
+|--------------|--------------|
+| OpenShift | v4.8 & 9 |
+| GKE | >= v1.21 |
While this solution is designed to easily extend to a Rancher use-case, Rancher
infrastructure is not required. Testing against labeled namespaces in standard
@@ -433,8 +428,8 @@ for infrastructure setup and long CI builds.
| **Title** | **Given** | **When** | **Then** | **Comment** |
|-----------|-----------|----------|----------|-------------|
-| **Login Happy Path** | Given the Kubernetes Authenticator `${service_id}` is configured to validate namespaces with label `x=y` | When a certificate injection request is received from a namespace labeled `x=y` | The the Authenticator responds with a 202 status and injects the certificate | |
-| **Authentication Happy Path** | Given the Kubernetes Authenticator `${service_id}` is configured to validate namespaces with label `x=y`` | When an authentication request is received from a namespace labeled `x=y` | Then the Authenticator responds with a 200 status and an access token | |
+| **Login Happy Path** | Given the Kubernetes Authenticator `${service_id}` is configured to validate namespaces with label `x=y` | When a certificate injection request is received from a namespace labeled `x=y` | Then authentication succeeds with a 202 status, certificate injection, and [new log **4**](#logs) | |
+| **Authentication Happy Path** | Given the Kubernetes Authenticator `${service_id}` is configured to validate namespaces with label `x=y` | When an authentication request is received from a namespace labeled `x=y` | Then authentication succeeds with a 200 status, an access token, and [new log **4**](#logs) | |
#### Security Tests
@@ -453,9 +448,10 @@ for infrastructure setup and long CI builds.
| **Title** | **Given** | **When** | **Then** | **Comment** |
|-----------|-----------|----------|----------|-------------|
-| **Misconfigured Authenticator** | Given that a policy file defines a Kubernetes Authenticator instance with both `authn-k8s.[namespace\|namespace-label-selector]` annotations | When the identity authenticates with Conjur | Authentication should fail with a 401 response and an `Errors::Authentication::Constraints` log. | |
-| **Misconfigured Identity** | Given that the Kubernetes Authenticator is configured to validate a namespace label, and its identity does not have permission to `get` namespaces in a cluster | When an authentication request is received | Then the request fails with a 500 response | |
-| **Misconfigured Namespace** | Given that a Kubernetes Authenticator is configured to authenticate requests from namespaces with the label `x=y` | When a requesting namespace does not have the label `x=y` | Then the request fails with a 401 response | |
+| **Misconfigured Authenticator** | Given that a policy file defines a Kubernetes Authenticator identity with both `authn-k8s.[namespace\|namespace-label]` annotations | When the identity authenticates with Conjur | Authentication should fail with a 401 response and [new log **0**](#logs). | |
+| **Misconfigured Identity** | Given that the Kubernetes Authenticator is configured to validate a namespace label, and its identity does not have permission to `get` namespaces in a cluster | When an authentication request is received | Then the request fails with a 404 response and a KubeClient log indicating the namespace was not found | |
+| **Misconfigured Namespace** | Given that a Kubernetes Authenticator is configured to authenticate requests from namespaces with the label `x=y` | When a requesting namespace does not have the label `x=y` | Then the request fails with a 401 response and [new log **1**](#logs) | |
+| **Misconfigured Label** | Given that a policy file defines a Kubernetes Authenticator identity with the `authn-k8s/namespace-label` annotation, but its value does not adhere to the format `=` | When the identity authenticates with Conjur | Authentication should fail with a 403 response and [new log **2**](#logs) | |
#### Performance Tests
@@ -470,13 +466,13 @@ for infrastructure setup and long CI builds.
[//]: # "If the logs are listed in the feature doc, add a link to that section. If not, list them here."
[//]: # "You can use this tool to generate a table - https://www.tablesgenerator.com/markdown_tables#"
-| **Scenario** | **Log message** |
-|--------------|-----------------|
-| An authenticating host is configured with either both or none of `authn-k8s/namespace` or `authn-k8s/namespace-label-selector` | Role must have exactly one of the following required constraints: {0} |
-| An authenticating host is configured with `authn-k8s/namespace-label-selector`, but the authenticating namespace does not conform | Kubernetes namespace {0} does not match label-selector {1} |
-| An authenticating host is configured with `authn-k8s/namespace-label-selector`, but its format does not match `"="` | Invalid namespace label selector {0}: must adhere to format "\=\" |
-| Kubernetes Authenticator begins validating `authn-k8s/namespace-label-selector` restriction | Validating resource restriction on request: 'namespace-label-selector' |
-| Kubernetes Authenticator successfully validates `authn-k8s/namespace-label-selector` restriction | Validated K8s resource. Type:'namespace-label-selector', Selector:'{0}', Namespace:'{1}' |
+| **ID** | **Scenario** | **Log message** |
+|--------|--------------|-----------------|
+| 0 | An authenticating host is configured with either both or none of `authn-k8s/namespace` or `authn-k8s/namespace-label` | Role must have exactly one of the following required constraints: {0} |
+| 1 | An authenticating host is configured with `authn-k8s/namespace-label`, but the authenticating namespace does not conform | Kubernetes namespace {0} does not match label-selector {1} |
+| 2 | An authenticating host is configured with `authn-k8s/namespace-label`, but its format does not match `"="` | Invalid namespace label selector {0}: must adhere to format "\=\" |
+| 3 | Kubernetes Authenticator begins validating `authn-k8s/namespace-label` restriction | Validating resource restriction on request: 'namespace-label' |
+| 4 | Kubernetes Authenticator successfully validates `authn-k8s/namespace-label` restriction | Validated K8s resource. Type:'namespace-label', Selector:'{0}', Namespace:'{1}' |
## Documentation
[//]: # "Add notes on what should be documented in this solution. Elaborate on where this should be documented, including GitHub READMEs and/or official documentation."
@@ -517,7 +513,7 @@ live currently.
- !host
id: test-app
annotations:
- authn-k8s/namespace-label-selector: "conjur.org/project=devNamespaces"
+ authn-k8s/namespace-label: "conjur.org/project=devNamespaces"
authn-k8s/authentication-container-name: "authenticator"
authn-k8s/service-account: "test-app-sa"
```
@@ -545,6 +541,17 @@ live currently.
This restriction may not be a barrier to acceptance, and shouldn't obstruct a
complete solution.
+2. Rancher uses
+ [field management](https://kubernetes.io/docs/reference/using-api/server-side-apply/#field-management)
+ to maintain labels describing Project memberships server-side.
+
+ For our users that want to use labeled namespace groups in vanilla
+ Kubernetes, should we suggest field management to secure labels? Should we
+ provide a suggested implementation?
+
+ Is this something that can be achieved by simply restricting `create`,
+ `update` and `patch` permissions on namespace resources?
+
## Definition of Done
- Solution designed is approved