containers kubernetes security Tanzu Application Platform tutorials

How to Install VMware Tanzu Application Platform with Transport Layer Security and Azure AD

This article is going to tackle the installation of VMware Tanzu Application Platform and securing the UI with transport layer security (TLS) and Microsoft Windows Azure Active Directory (Azure AD). But first, what is the Tanzu Application Platform?

VMware Tanzu Application Platform is a modular, application-aware platform that provides a rich set of developer tooling and a pre-paved path to production. Additionally, it allows developers to build and deploy software quickly and securely on any compliant public cloud or on-premises Kubernetes cluster.

Below is a great diagram of what Tanzu Application Platform is conceptually. For a more in-depth look at how Tanzu Application Platform works, read this article by Gowtham Shankar.

Installing Tanzu Application Platform is pretty straightforward, but there are still a few gotchas that this post will help out with.

  1. First, please have a look at the prerequisites
  2. You will also need to have access to VMware Tanzu Network.
  3. From Tanzu Network, download the Tanzu command line interface (CLI) for your OS and then unpack it.
  4. Next, you will need to download Cluster Essentials for VMware Tanzu here.
  5. Make sure you have accepted all applicable EULAs.
  6. You will also need a domain and to carve out a subdomain particularly for Tanzu Application Platform. Please note that a registry is required—for all of the examples below, Harbor will be used.

With all that out of the way, let's get started by setting up some useful exports.

export INSTALL_BUNDLE=registry.tanzu.vmware.com/tanzu-cluster-essentials/cluster-essentials-bundle@sha256:ab0a3539da241a6ea59c75c0743e9058511d7c56312ea3906178ec0f3491f51d
export INSTALL_REGISTRY_HOSTNAME=registry.tanzu.vmware.com
export INSTALL_REGISTRY_USERNAME=TANZU-NET-USER
export INSTALL_REGISTRY_PASSWORD=TANZU-NET-PASSWORD
export TAP_VERSION=1.1.0

Note that the above INSTALL_BUNDLE is for Tanzu Application Platform 1.1.x. If you are attempting to install something older than this version, you will need to look through the Tanzu Application Platform docs to get the correct INSTALL_BUNDLE.

Create a namespace to install Tanzu Application Platform into.

kubectl create ns tap-install

You will now need to cd into the directory where you untarred the Tanzu Cluster Essentials.

cd $HOME/tanzu-cluster-essentials ## Or wherever you have cluster-essentials untarred

Run the installer script.

./install.sh --yes

If everything completes successfully you can move on to copying kapp to our path.

sudo cp $HOME/tanzu-cluster-essentials/kapp /usr/local/bin/kapp ##Or wherever you have cluster-essentials untarred

Next,install the Tanzu CLI.

export TANZU_CLI_NO_INIT=true
cd $HOME/tanzu  # or wherever you downloaded the cli
install cli/core/VERSION/tanzu-core-darwin_amd64 /usr/local/bin/tanzu

Be sure to check your version.

tanzu version

Once the version is confirmed, complete a clean install of the plug-ins.

tanzu plugin clean

cd $HOME/tanzu  # again wherever you have downloaded this
tanzu plugin install --local cli all  # make sure you are not in the cli directory when you do this go one directory above it

Check the plug-ins.

tanzu plugin list

You’ll need to create a container registry secret (i.e., Docker registry secret).

tanzu secret registry add tap-registry 
  --username ${INSTALL_REGISTRY_USERNAME} --password ${INSTALL_REGISTRY_PASSWORD} 
  --server ${INSTALL_REGISTRY_HOSTNAME} 
  --export-to-all-namespaces --yes --namespace tap-install

Add the Tanzu Application Platform package repository to the cluster by running:

tanzu package repository add tanzu-tap-repository 
  --url registry.tanzu.vmware.com/tanzu-application-platform/tap-packages:$TAP_VERSION 
  --namespace tap-install

Get the status of the Tanzu Application Platform package repository, and ensure the status updates to “reconcile” succeeded by running:

tanzu package repository get tanzu-tap-repository --namespace tap-install

Next, you’ll need to create a Tanzu Application Platform values file. Below are a few simple options, but again, our end goal is to have TLS and Azure AD in our final install.

You can find an example of a values file here. Below is an example of a standard Tanzu Application Platform values file.

profile: full
ceip_policy_disclosed: true # Installation fails if this is set to 'false'
buildservice:
  kp_default_repository: myharbor.com/tap/build-service
  kp_default_repository_username: YOUR_REGISTRY_USER
  kp_default_repository_password: YOUR_REGISTRY_PASSWORD
  tanzunet_username: YOUR_TANZU_USERNAME
  tanzunet_password: YOUR_TANZU_PASSWORD
  descriptor_name: "full"
  enable_automatic_dependency_updates: true
supply_chain: basic

cnrs:
  domain_name: tap.alexanderbrash.dev
  domain_template: "{{.Name}}-{{.Namespace}}.{{.Domain}}"

ootb_supply_chain_basic:
  registry:
    server: myharbor.com
    repository: "tap/supply-chain"
  gitops:
    ssh_secret: ""

learningcenter:
  ingressDomain: "learningcenter.tap.alexanderbrash.dev"

tap_gui:
  service_type: ClusterIP
  ingressEnabled: "true"
  ingressDomain: "tap.alexanderbrash.dev"
  app_config:
    app:
      baseUrl: http://tap-gui.tap.alexanderbrash.dev  #Note this must be called tap-gui I tried tap-ui and it did not work
    catalog:
      locations:
        - type: url
          target: https://github.com/badraoul/tap-test/blob/main/blank/catalog-info.yaml
    backend:
      baseUrl: http://tap-gui.tap.alexanderbrash.dev #Note this must be called tap-gui I tried tap-ui and it did not work
      cors:
        origin: http://tap-gui.tap.alexanderbrash.dev #Note this must be called tap-gui I tried tap-ui and it did not work

metadata_store:
  app_service_type: LoadBalancer # (optional) Defaults to LoadBalancer. Change to NodePort for distributions that don't support LoadBalancer

grype:
  namespace: "default" # (optional) Defaults to default namespace.
  targetImagePullSecret: "tap-registry"

contour:
  envoy:
    service:
      type: LoadBalancer

The following is an example utilizing Amazon Web Services Network Load Balancer (AWS NLB).

profile: full
ceip_policy_disclosed: true # Installation fails if this is set to 'false'
buildservice:
  kp_default_repository: myharbor.com/tap/build-service
  kp_default_repository_username: HARBOR_USER
  kp_default_repository_password: HARBOR_PASSWORD
  tanzunet_username: TANZU_NET_USER
  tanzunet_password: TANZU_NET_PASSWORD
  descriptor_name: "tap-1.0.0-full"
  enable_automatic_dependency_updates: true
supply_chain: basic

cnrs:
  domain_name: alexanderbrash.dev

ootb_supply_chain_basic:
  registry:
    server: myharbor.com
    repository: "tap/supply-chain"
  gitops:
    ssh_secret: ""

learningcenter:
  ingressDomain: "lab.alexanderbrash.dev"

tap_gui:
  service_type: ClusterIP
  ingressEnabled: "true"
  ingressDomain: "alexanderbrash.dev"
  app_config:
    app:
      baseUrl: http://tap-gui.alexanderbrash.dev
    catalog:
      locations:
        - type: url
          target: https://github.com/badraoul/tap-test/blob/main/blank/catalog-info.yaml
    backend:
      baseUrl: http://tap-gui.alexanderbrash.dev
      cors:
        origin: http://tap-gui.alexanderbrash.dev

metadata_store:
  app_service_type: LoadBalancer # (optional) Defaults to LoadBalancer. Change to NodePort for distributions that don't support LoadBalancer

grype:
  namespace: "default" # (optional) Defaults to default namespace.
  targetImagePullSecret: "tap-registry"

contour:
  infrastructure_provider: aws
  envoy:
    service:
      aws:
        LBType: nlb

Below is the desired outcome and an example of using TLS.

profile: full
ceip_policy_disclosed: true # Installation fails if this is set to 'false'
buildservice:
  kp_default_repository: myharbor.com/tap/build-service
  kp_default_repository_username: HARBOR_USER
  kp_default_repository_password: HARBOR_PASSWORD
  tanzunet_username: TANZU_NET_USER
  tanzunet_password: TANZU_NET_PASSWORD
  descriptor_name: "full"
  enable_automatic_dependency_updates: true
supply_chain: basic

cnrs:
  domain_name: tap-lab.alexanderbrash.net
  domain_template: "{{.Name}}-{{.Namespace}}.{{.Domain}}"
  default_tls_secret: tls-certs/tap-lab-alexbrash-net-wldcrd

ootb_supply_chain_basic:
  registry:
    server: myharbor.com
    repository: "tap/supply-chain"
  gitops:
    ssh_secret: ""

learningcenter:
  ingressDomain: "learningcenter.tap-lab.alexanderbrash.net"

tap_gui:
  service_type: ClusterIP
  ingressEnabled: "true"
  ingressDomain: "tap-lab.alexanderbrash.net"
  tls:
    secretName: tap-lab-alexbrash-net-wldcrd
    namespace: tls-certs
  app_config:
    app:
      baseUrl: https://tap-gui.tap-lab.alexanderbrash.net
    catalog:
      locations:
        - type: url
          target: https://github.com/badraoul/tap-test/blob/main/blank/catalog-info.yaml
    backend:
      baseUrl: https://tap-gui.tap-lab.alexanderbrash.net
      cors:
        origin: https://tap-gui.tap-lab.alexanderbrash.net

metadata_store:
  app_service_type: LoadBalancer # (optional) Defaults to LoadBalancer. Change to NodePort for distributions that don't support LoadBalancer

grype:
  namespace: "default" # (optional) Defaults to default namespace.
  targetImagePullSecret: "tap-registry"

contour:
  envoy:
    service:
      type: LoadBalancer

For TLS to work you need to create a TLS delegation for Envoy and a namespace to keep the TLS secrets.

So first, create the namespace.

kubectl create ns tls-certs

Next, build the TLS delegation resource.

cat <<EOF > tls-delegation.yaml
apiVersion: projectcontour.io/v1
kind: TLSCertificateDelegation
metadata:
  name: tap-lab-alexbrash-net-wldcrd
  namespace: tls-certs
spec:
  delegations:
    - secretName: tap-lab-alexbrash-net-wldcrd
      targetNamespaces:
      - "*"

EOF
kubectl apply -f tls-delegation.yaml

Now, create the certificate in the TLS-certs namespace.

kubectl create secret tls tap-lab-alexbrash-net-wldcrd --key cert-key.pem --cert cert.pem -n tls-certs

After that, add Azure AD. By default, the Tanzu Application Platform GUI uses a guest account, but backstage supports different authentication providers (you can find a list here).

Another reason TLS is added to the Tanzu Application Platform GUI is that it's required to enable authentication.

Inside the Azure Portal, head over to "Azure Active Directory," then under "App registrations" click on "New registration." From here, simply give it a name, then under "Supported account types" select the appropriate option for your organization. (In this example,  the default option was selected.) Last, under "Redirect URI" select "Web" for platform. 

Next, enter the below uniform resource identifier (URI):

https://tap-gui.yourdomain/api/auth/microsoft/handler/frame

You will then need to create a client secret. Under "Certificates and secrets" select "New client secret" and follow the prompts. Please note that your client secret is the "Value" not the Secret ID. (I made that mistake and was troubleshooting why things were not working for a while.)

For the values file you will need the following three things:

  1. client ID
  2. tenant ID
  3. client secret

Your values file will now look like this:

profile: full
ceip_policy_disclosed: true # Installation fails if this is set to 'false'
buildservice:
  kp_default_repository: HARBOR_REGISTRY_URL/tap/build-service
  kp_default_repository_username: HARBOR_USER
  kp_default_repository_password: HARBOR_PASSWORD
  tanzunet_username: TANZU_NET_USER
  tanzunet_password: TANZU_NET_PASSWORD
  descriptor_name: "full"
  enable_automatic_dependency_updates: true
supply_chain: basic

cnrs:
  domain_name: tap.alexanderbrash.dev
  domain_template: "{{.Name}}-{{.Namespace}}.{{.Domain}}"
  default_tls_secret: tls-certs/tap-alexbrash-dev-wildcard

ootb_supply_chain_basic:
  registry:
    server: HARBOR_REGISTRY_URL
    repository: "tap/supply-chain"
  gitops:
    ssh_secret: ""

learningcenter:
  ingressDomain: "learningcenter.tap.alexanderbrash.dev"

tap_gui:
  service_type: ClusterIP
  ingressEnabled: "true"
  ingressDomain: "tap.alexanderbrash.dev"
  tls:
    secretName: tap-alexbrash-dev-wildcard
    namespace: tls-certs
  app_config:
    auth:
      allowGuestAccess: false
      environment: development
      providers:
        microsoft:
          development:
            clientId: AZURE_CLIENTID
            clientSecret: AZURE_CLIENT_SECRET
            tenantId: AZURE_TENANTID
    app:
      baseUrl: https://tap-gui.tap.alexanderbrash.dev
    catalog:
      locations:
        - type: url
          target: https://github.com/badraoul/tap-test/blob/main/blank/catalog-info.yaml
    backend:
      baseUrl: https://tap-gui.tap.alexanderbrash.dev
      cors:
        origin: https://tap-gui.tap.alexanderbrash.dev

metadata_store:
  app_service_type: LoadBalancer # (optional) Defaults to LoadBalancer. Change to NodePort for distributions that don't support LoadBalancer

grype:
  namespace: "default" # (optional) Defaults to default namespace.
  targetImagePullSecret: "tap-registry"

contour:
  envoy:
    service:
      type: LoadBalancer

With all that out of the way, let's install the Tanzu Application Platform.

tanzu package install tap -p tap.tanzu.vmware.com -v $TAP_VERSION --values-file tap-values.yml -n tap-install

You will need to ensure that all packages are reconciling successfully.

tanzu package installed list -n tap-install

Please note: install times depend on the available resources in your cluster. With that in mind, I recommend at least four m5.x large nodes (i.e.g, four nodes that are 4vCPUs and 16GB of RAM with at least 70GB of disk space).

A successful reconciliation looks like the image below:

And that's it—you now have the Tanzu Application Platform up and running!