July 31, 2023
TAP 1.6 – Namespace Provisioner Improvements
What Is The TAP Namespace Provisioner
Namespace Provisioner provides a secure, automated way for platform operators to provision namespaces with the resources and namespace-level privileges required for their workloads to function as intended. It enables operators to add additional customized namespace-scoped resources using GitOps to meet their organization’s requirements and provides continuous reconciliation using the kapp-controller to maintain the actual desired state of the namespace-scoped resources.
Why Is This Needed
For anyone that dealt with TAP before TAP 1.4, they know the experience of “Preparing a developer namespace”. As TAP is a fully kubernetes based solution, almost all configuration is done via kubernetes YAML manifests. TAP is such a powerful system, covering so many areas in the development lifecycle and the path to production, which is amazing however, this also means that lots of resources, credentials, templates, etc. must be created in a namespace in order to provide the developer with the needed permissions to deploy their applications.
The “wall of YAML” that was needed to prepare a namespace manually was not a great experience, and was often a true burden on the platform team, and caused for difficulties and delays in the onboarding of new applications to the platform.
What Is New In TAP 1.6
TAP 1.6 offers some really nice simplifications for previously tedious options. Some of the key new features include:
A simplified way to skip creation of certain OOTB resources NSP typically would install
A simplified way to manage the default service account in NSP managed namespaces
Support for lists and objects to be passed to NSP via annotations
Simplified TAP Values to not need to provide the path value in the additional_sources stanza
Let’s take a look at each of these improvements and see what they offer.
Skipping OOTB Resources
One of the nice elements of TAP is that it is a batteries included solution, but the batteries are swappable.
When using the testing and scanning supply chain, by default the scanner which is used is grype.
While Grype is a good solution, many companies want to use other scanners, either OSS like trivy, or commercial like Prisma, Aqua, Carbon Black, Snyk etc.
NSP when used in a cluster with the testing and scanning supply chain configured, by default installs the grype package for each managed namespace in order to support a seamless experience.
While this is great for those that use Grype, it was a pain for those that wanted to use a different scanner.
In TAP 1.6, we now have a new option which allows us to disable grype installation either globally or at the per namespace level.
To disable Grype at the global level, in your TAP values file you can now simply add:
namespace_provisioner:
default_parameters:
skip_grype: true
This will skip the grype installation for all namespaces. If however you want to do this at the per namespace level instead you can simply add the following label or annotation to your namespace:
# via annotation
kubectl annotate ns YOUR_NAMESPACE_NAME param.nsp.tap/skip_grype=true
# via label
kubectl label ns YOUR_NAMESPACE_NAME param.nsp.tap/skip_grype=true
This can also be done via the gitops mechanism by adding the “skip_grype” parameter to the namespaces definition:
#@data/values
---
namespaces:
- name: dev
skip_grype: true
As you can see, this is a much better experience then in previous versions, and allows for easily integrating with other scanners when so desired.
This is also possible to disable the automatic adding of limit ranges per namespace via a similar mechanism where the only difference is the parameter name, which instead of being skip_grype, is skip_limit_range:
namespace_provisioner:
default_parameters:
skip_limit_range: true
Managing Service Account Secrets
One of the resources that TAP manages for us via NSP in every developer namespace, is the default service account.
This is the service account that by default will be used for applying and managing our workloads.
When using TAP in a GitOps flow topology, we need to add a Git secret to this service account in order to support both pulling down source code from private repositories, as well as to push the generated kubernetes YAML to our Git repositories.
In TAP 1.6, the process of managing this has becoming much more streamlined. Lets see how you would do this now in TAP 1.6:
The first step is to create a secret with the needed values in the tap-install namespace:
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: git-creds-for-workloads
namespace: tap-install
type: Opaque
stringData:
content.yaml: |
git:
host: GIT-SERVER-URL
username: GIT-USERNAME
password: GIT-PASSWORD-OR-TOKEN
EOF
Next we need to add a file to our NSP git repository with the following content:
#@ load("@ytt:data", "data")
#@ load("@ytt:base64", "base64")
---
apiVersion: v1
kind: Secret
metadata:
name: git-creds
annotations:
tekton.dev/git-0: #@ data.values.imported.git.host
type: kubernetes.io/basic-auth
data:
username: #@ base64.encode(data.values.imported.git.username)
password: #@ base64.encode(data.values.imported.git.password)
Note that this file has no credentials or FQDNs in it, rather we are using YTT to template this secret for us, and will use the secret from above in the first step to fill in the needed values at runtime.
Next we need to configure NSP to reference our git repository with the above defined YTT template, as well as our secret we created with the git authentication details:
namespace_provisioner:
additional_sources:
- git:
ref: origin/main
subPath: ns-provisioner-samples/credentials
url: https://github.com/vmware-tanzu/application-accelerator-samples.git
import_data_values_secrets:
- name: git-creds-for-workloads
namespace: tap-install
create_export: true
default_parameters:
supply_chain_service_account:
secrets:
- git
As can be seen above, we are actually using the sample from vmware with the same yaml definition in Git as provided above, but this can also be hosted in your own repo if you so desire.
We can also set this at a per namespace level by simply removing the “default_parameters” section from the NSP section in our TAP values, and provide which secrets to add to our workload via annotations on our namespace:
kubectl annotate ns YOUR_NS \
param.nsp.tap/supply_chain_service_account.secrets='["git-creds"]'
and if mulitple secrets were needed, for example when also doing the cosign integration within a supply chain you could simply add that to the array:
kubectl annotate ns YOUR_NS \
param.nsp.tap/supply_chain_service_account.secrets='["git-creds","cosign-creds"]'
While above this is setting the service accounts secrets, the same is possible for image pull secrets via the same mehanism simply replacing the “secrets” key for “imagePullSecrets” wither via the annotation or via the TAP values for a global setting, or also via the NSP GitOps model by adding the same configuration in your desired namespaces yaml file.
Arrays And Objects Via Annotations
sometimes, we need to pass a set of values related to one another into NSP for a specific namespace, in order to provide the right level of customization and automation for our environments.
NSP now supports the ability as seen above in the managing secrets section, to pass in arrays as well as json objects to NSP as parameters via annotations which will be automatically parsed correctly into the relevant types in NSP.
If we want to pass in an array value we can simply provide the value of our array within single quotes and square brackets as an annotation, and for an object within single quotes, we simply use curly brackets. Lets see a few examples and what they will end up looking like:
kubectl annotate ns dev-ns \
param.nsp.tap/basic.array='["sample-1","sample-2","sample-3"]'
kubectl annotate ns dev-ns \
param.nsp.tap/basic.object='{"s1":"v1","s2":"v2"}'
kubectl annotate ns dev-ns \
param.nsp.tap/advanced='[{"s1":"v1","s2":"v2"},{"s3":"v3"}]'
With the above samples, we would recieve the following in our desired namespaces configmap:
#@data/values
---
namespaces:
- name: dev-ns
advanced:
- s1: v1
s2: v2
- s3: v3
basic:
array:
- sample-1
- sample-2
- sample-3
object:
s1: v1
s2: v2
while the above is just an example, the options this unlocks are truly exciting. you could via a few annotations enable auto creatuin of AppSSO Auth servers, Backing services via class claims, Spring Cloud Gateway configurations, ACS configurations, a dedicated API portal per namespace, and much more.
Simplified additional sources section of TAP values
The final improvement i want to mention is that you no longer need to provide the path parameter when using the additional_sources section in your TAP values.
previously, for every additional git source you provided, you needed to specify a path to which the files in that repo would be synced to. Now in TAP 1.6, this can still be provided, but if it is not provided, a default value will be created for you, making it one less thing to configure and mess up!
Summary
As you can see, a lot of nice features have been added to NSP in this release. While none are game changers, the simplicity it provides is a huge benefit, and will make managing NSP configurations a much lower barrier for entry than before, allowing more customers to provide better value and more customized experiences to the platforms end users!