TLS Configuration Management

Before you install GoodData.CN, review the different options for managing Transport Layer Security (TLS) certificates. Understanding what will be required by the Organizations you create before you install GoodData.CN will help you determine which configuration is best for your site.

Every Organization has its own hostname that is bound to the Kubernetes Ingress resource. All services for a given organization are available on this hostname. To keep data secure when transferred between the client and the server, TLS is used.

How you manage your TLS certificates depends on how you deploy the frontend load balancer.

TLS Terminated on Load Balancer

The frontend load balancer is assigned a TLS certificate and handles the decryption of incoming traffic. Requests are then routed unencrypted to the Ingress controller.

Many cloud-native Load Balancers support only one certificate, so this method is suitable only for wildcard certificates such as *.cust.company.com. All organizations' hostnames must match this wildcard, for example, organization1.cust.company.com, another.cust.company.com, and so on.

Do not include the tls section in the Organization resource:

kind: Organization
metadata:
  name: some-org
  namespace: gooddata-cn
...
spec:
  id: organization1
  name: The First Organization
  hostname: org-one.customers.example.com
  adminGroup: adminGroup
  adminUser: admin
  adminUserToken: "$5$1234567890123456$pA9PBFxCwLbVOB.fImbUCUjoyQblla4EdSkHhVmy9A7"
  # tls: TLS section must not be present

TLS Terminated on Ingress Controller

The frontend load balancer passes encrypted traffic directly to the Ingress controller. TLS decryption is performed in the Ingress controller with a certificate matching the Ingress hostname. This means that an organization can have any hostname so long as the certificate for this hostname is available to the Ingress controller.

There are three ways to assign certificates to an Ingress:

Manual Certificate Management

The certificate for every organization must be manually loaded as a Secret to the same namespace where GoodData.CN is deployed. As an example, assume you have the customer’s key and certificate stored in local files some-org.key and some-org.crt. The Secret can be created using the following command:

kubectl create secret tls secret-with-cert-for-some-org \
  --cert=some-org.crt --key=some-org.key --namespace=gooddata-cn

In the Organization resource, you create a reference to this Secret in the spec.tls.secretName field. Other tls fields (like issuerType or issuerName) must NOT be used.

kind: Organization
metadata:
  name: some-org
  namespace: gooddata-cn
...
spec:
  id: organization1
  name: The First Organization
  hostname: analytics.org-one.com
  adminGroup: adminGroup
  adminUser: admin
  adminUserToken: "$5$1234567890123456$pA9PBFxCwLbVOB.fImbUCUjoyQblla4EdSkHhVmy9A7"
  tls:
    # this Secret needs to be pre-created manually
    secretName: secret-with-cert-for-some-org
    # issuerType: is ignored when issuerName is not set
    # issuerName: must NOT be used

Certificates Issued by an Internal Certificate Authority which Integrates with cert-manager

If your company has its own Certificate Authority (CA) for issuing certificates, you can use these certificates for all Organizations you create. You need to make the client web browsers trust your CA, so using this method is meaningful only for company-wide deployment where you have control over the web browser configuration of your clients.

Cert-manager integrates with various CA systems. Refer to cert-manager’s documentation for more details. Commonly used issuer types are as follows:

  • CA - cert-manager’s own Certificate Authority
  • Vault - CA built on top of existing HashiCorp Vault
  • External - Projects providing an issuer interface to other systems, such as AWS Private CA, FreeIPA, Google Cloud CA, or MS Active Directory.

As an example, assume you will use the “CA”-type issuer and already have a CA key and certificate pair in ca.key and ca.crt. Your setup will look similar to the following configuration:

# Kubernetes secret with CA key and certificate. You can
# also create this Secret directly from command-line using:
# kubectl create secret tls company-ca-key-pair \
#    --cert=ca.crt --key=ca.key --namespace=gooddata-cn
---
apiVersion: v1
kind: Secret
metadata:
  name: company-ca-key-pair
  namespace: gooddata-cn
data:
  # base64-encoded CA certificate (PEM)
  tls.crt: LS0tLS1CRUdJTiBDRVJUSU...
  # base64-encoded key belonging to CA certificate (PEM)
  tls.key: LS0tLS1CRUdJTiBSU0EgUF...

Then, create an issuer of type ca:

# CA Issuer
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: ca-issuer
  namespace: gooddata-cn
spec:
  ca:
    secretName: company-ca-key-pair

Cert-manager supports two kinds of issuers:

  1. Issuer: Operation is limited to a given namespace where this resource is created.
  2. ClusterIssuer: Cluster-wide resource accessible from any namespace.

If you plan to use cert-manager’s CA for other applications running in different namespaces, you can create ClusterIssuer instead of Issuer:

# CA ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: ca-issuer
spec:
  ca:
    secretName: company-ca-key-pair

Keep in mind that for ClusterIssuer, the referenced Secret company-ca-key-pair must be in the same namespace where the cert-manager’s controller is deployed (usually the cert-manager namespace).

Certificates Issued by Let’s Encrypt which Integrates with cert-manager

The last method of obtaining TLS certificates is to use the public CA Let’s Encrypt. The Let’s Encrypt CA is trusted by all major web browsers and operating systems. cert-manager also supports the Let’s Encrypt CA and its ACME protocol.

You can use this method for automated provisioning of certificates for publicly accessible deployments where you can’t manage the clients’ browsers trusted certificates.

To use the Let’s Encrypt service for issuing TLS certificates to your customers' Organization hostnames, you need to configure Issuer (or ClusterIssuer) to use the ACME protocol and HTTP01 solver.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-issuer
spec:
  acme:
    # You must replace this email address with your own.
    # Let's Encrypt will use this to contact you about expiring
    # certificates, and issues related to your account.
    email: user@example.com
    # After you properly test the Issuer functionality, you should
    # switch to `https://acme-v02.api.letsencrypt.org/directory`
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      # Secret resource that will be used to store the account's private key.
      name: letsencrypt-issuer-account-key
    # Add a single challenge solver, HTTP01 using nginx
    solvers:
    - http01:
        ingress:
          class: nginx

You can refer to Cert-manager Integration with Let’s Encrypt for more details about Cert-manager installation.