Automatically Rotating Webhook TLS Credentials

    By default, when Linkerd is installed with the Linkerd CLI or with the Linkerd Helm chart, TLS credentials are automatically generated for all of the webhooks. If these certificates expire or need to be regenerated for any reason, performing a Linkerd upgrade (using the Linkerd CLI or using Helm) will regenerate them.

    This workflow is suitable for most users. However, if you need these webhook certificates to be rotated automatically on a regular basis, it is possible to use cert-manager to automatically manage them.

    As a first step, and create the namespaces that cert-manager will use to store its webhook-related resources. For simplicity, we suggest using the defaule namespace linkerd uses:

    Save the signing key pair as a Secret

    Next, we will use the tool, to create a signing key pair which will be used to sign each of the webhook certificates:

    1. step certificate create webhook.linkerd.cluster.local ca.crt ca.key \
    2. --profile root-ca --no-password --insecure --san webhook.linkerd.cluster.local
    3. kubectl create secret tls webhook-issuer-tls --cert=ca.crt --key=ca.key --namespace=linkerd
    4. # ignore if not using the viz extension
    5. kubectl create secret tls webhook-issuer-tls --cert=ca.crt --key=ca.key --namespace=linkerd-viz
    6. # ignore if not using the jaeger extension
    7. kubectl create secret tls webhook-issuer-tls --cert=ca.crt --key=ca.key --namespace=linkerd-jaeger

    Issuing certificates and writing them to secrets

    Finally, we can create cert-manager “Certificate” resources which use the Issuers to generate the desired certificates:

    1. cat <<EOF | kubectl apply -f -
    2. apiVersion: cert-manager.io/v1
    3. kind: Certificate
    4. metadata:
    5. name: linkerd-proxy-injector
    6. namespace: linkerd
    7. spec:
    8. secretName: linkerd-proxy-injector-k8s-tls
    9. duration: 24h
    10. renewBefore: 1h
    11. issuerRef:
    12. name: webhook-issuer
    13. kind: Issuer
    14. commonName: linkerd-proxy-injector.linkerd.svc
    15. dnsNames:
    16. - linkerd-proxy-injector.linkerd.svc
    17. isCA: false
    18. privateKey:
    19. algorithm: ECDSA
    20. usages:
    21. - server auth
    22. ---
    23. apiVersion: cert-manager.io/v1
    24. kind: Certificate
    25. metadata:
    26. name: linkerd-sp-validator
    27. namespace: linkerd
    28. secretName: linkerd-sp-validator-k8s-tls
    29. duration: 24h
    30. renewBefore: 1h
    31. issuerRef:
    32. name: webhook-issuer
    33. commonName: linkerd-sp-validator.linkerd.svc
    34. dnsNames:
    35. - linkerd-sp-validator.linkerd.svc
    36. isCA: false
    37. privateKey:
    38. algorithm: ECDSA
    39. usages:
    40. - server auth
    41. ---
    42. # ignore if not using the viz extension
    43. apiVersion: cert-manager.io/v1
    44. kind: Certificate
    45. metadata:
    46. name: tap
    47. namespace: linkerd-viz
    48. spec:
    49. secretName: tap-k8s-tls
    50. duration: 24h
    51. renewBefore: 1h
    52. issuerRef:
    53. name: webhook-issuer
    54. kind: Issuer
    55. commonName: tap.linkerd-viz.svc
    56. dnsNames:
    57. - tap.linkerd-viz.svc
    58. isCA: false
    59. privateKey:
    60. algorithm: ECDSA
    61. usages:
    62. - server auth
    63. ---
    64. # ignore if not using the viz extension
    65. apiVersion: cert-manager.io/v1
    66. kind: Certificate
    67. metadata:
    68. name: linkerd-tap-injector
    69. namespace: linkerd-viz
    70. secretName: tap-injector-k8s-tls
    71. duration: 24h
    72. renewBefore: 1h
    73. issuerRef:
    74. name: webhook-issuer
    75. commonName: tap-injector.linkerd-viz.svc
    76. dnsNames:
    77. - tap-injector.linkerd-viz.svc
    78. isCA: false
    79. privateKey:
    80. algorithm: ECDSA
    81. usages:
    82. - server auth
    83. ---
    84. # ignore if not using the jaeger extension
    85. apiVersion: cert-manager.io/v1
    86. kind: Certificate
    87. metadata:
    88. name: jaeger-injector
    89. namespace: linkerd-jaeger
    90. spec:
    91. secretName: jaeger-injector-k8s-tls
    92. duration: 24h
    93. renewBefore: 1h
    94. issuerRef:
    95. name: webhook-issuer
    96. kind: Issuer
    97. commonName: jaeger-injector.linkerd.svc
    98. dnsNames:
    99. - jaeger-injector.linkerd.svc
    100. isCA: false
    101. privateKey:
    102. algorithm: ECDSA
    103. usages:
    104. - server auth
    105. EOF

    At this point, cert-manager can now use these Certificate resources to obtain TLS credentials, which are stored in the linkerd-proxy-injector-k8s-tls, linkerd-sp-validator-k8s-tls, tap-k8s-tls, tap-injector-k8s-tls and jaeger-injector-k8s-tls secrets respectively.

    Now we just need to inform Linkerd to consume these credentials.

    To configure Linkerd to use the credentials from cert-manager rather than generating its own, we generate a supplemental config file:

    1. linkerd install --values=config.yml | kubectl apply -f -
    2. # ignore if not using the viz extension
    3. linkerd viz install --values=config-viz.yml | kubectl apply -f -
    4. # ignore if not using the jaeger extension

    Installing with Helm

    For Helm installation, we can configure the Helm values directly:

    Note

    When installing Linkerd with Helm, you must also provide the issuer trust root and issuer credentials as described in Installing Linkerd with Helm.

    Note

    See for details on how to do something similar for control plane credentials.