Skip to content

Commit 1a06b26

Browse files
author
autero1
authored
Merge pull request #31 from gruntwork-io/gke_ssl_cert
Add support for Google managed ssl certificates
2 parents 5c0b718 + c25b928 commit 1a06b26

File tree

7 files changed

+129
-0
lines changed

7 files changed

+129
-0
lines changed

charts/k8s-service/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ This Helm Chart can also be used to front the `Pods` of the `Deployment` resourc
1313
[Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) rules to further configure complex routing
1414
rules in front of the `Service`.
1515

16+
If you're using the chart to deploy to [GKE](https://cloud.google.com/kubernetes-engine/), you can also use the chart to deploy a [Google Managed SSL Certificate](https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs) and associate it with the Ingress.
17+
1618

1719
## How to use this chart?
1820

@@ -38,6 +40,8 @@ The following resources will be deployed with this Helm Chart, depending on whic
3840
the `Deployment`. This manages how many pods can be disrupted by a voluntary disruption (e.g
3941
node maintenance). Created if you specify a non-zero value for the `minPodsAvailable` input
4042
value.
43+
- `ManagedCertificate`: The `ManagedCertificate` is a [GCP](https://cloud.google.com/) -specific resource that creates a Google Managed SSL certificate. Google-managed SSL certificates are provisioned, renewed, and managed for your domain names. Read more about Google-managed SSL certificates [here](https://cloud.google.com/load-balancing/docs/ssl-certificates#managed-certs). Created only if you configure the `google.managedCertificate` input (and set
44+
`google.managedCertificate.enabled = true` and `google.managedCertificate.domainName = your.domain.name`).
4145

4246

4347
## How do I expose my application internally to the cluster?
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{{- /*
2+
If the operator configures the google.managedCertificate input variable, then also create a ManagedCertificate resource
3+
that will provision a Google managed SSL certificate.
4+
*/ -}}
5+
{{- if .Values.google.managedCertificate.enabled -}}
6+
{{- /*
7+
We declare some variables defined on the Values. These are reused in `with` and `range` blocks where the scoped variable
8+
(`.`) is rebound within the block.
9+
*/ -}}
10+
{{- $fullName := include "k8s-service.fullname" . -}}
11+
{{- $domainName := .Values.google.managedCertificate.domainName -}}
12+
apiVersion: networking.gke.io/v1beta1
13+
kind: ManagedCertificate
14+
metadata:
15+
name: {{ $fullName }}
16+
labels:
17+
gruntwork.io/app-name: {{ .Values.applicationName }}
18+
# These labels are required by helm. You can read more about required labels in the chart best practices guide:
19+
# https://docs.helm.sh/chart_best_practices/#standard-labels
20+
app.kubernetes.io/name: {{ include "k8s-service.name" . }}
21+
helm.sh/chart: {{ include "k8s-service.chart" . }}
22+
app.kubernetes.io/instance: {{ .Release.Name }}
23+
app.kubernetes.io/managed-by: {{ .Release.Service }}
24+
spec:
25+
domains:
26+
- {{ $domainName }}
27+
{{- end }}

charts/k8s-service/values.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,29 @@ tolerations: []
333333
# imagePullSecrets lists the Secret resources that should be used for accessing private registries. Each item in the
334334
# list is a string that corresponds to the Secret name.
335335
imagePullSecrets: []
336+
337+
#----------------------------------------------------------------------------------------------------------------------
338+
# GOOGLE SPECIFIC VALUES
339+
# google specifies Google (GKE) specific configuration to be set via arguments/env. variables
340+
#----------------------------------------------------------------------------------------------------------------------
341+
google:
342+
# managedCertificate can be used to provision a Google Managed Certificate. Associate the ManagedCertificate object
343+
# to an Ingress by adding an annotation 'networking.gke.io/managed-certificates' to the Ingress.
344+
#
345+
# The expected keys are:
346+
# - enabled (bool) (required) : Whether or not the ManagedCertificate resource should be created.
347+
# - domainName (string) : Specifies the domain that the SSL certificate will be created for
348+
#
349+
# The following example specifies a ManagedCertificate with a domain name 'api.acme.com':
350+
#
351+
# EXAMPLE:
352+
#
353+
# google:
354+
# managedCertificate:
355+
# enabled: true
356+
# domainName: api.acme.com
357+
#
358+
# NOTE: if you enable managedCertificate, then Ingress must also be enabled.
359+
# Use a Google Managed Certificate. By default, turn off.
360+
managedCertificate:
361+
enabled: false

test/Gopkg.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/Gopkg.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
name = "github.com/gruntwork-io/terratest"
3030
version = "0.17.6"
3131

32+
[[constraint]]
33+
name = "github.com/GoogleCloudPlatform/gke-managed-certs"
34+
version = "0.3.4"
35+
3236
[prune]
3337
go-tests = true
3438
unused-packages = true

test/k8s_service_template_render_helpers_for_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"github.com/stretchr/testify/require"
1414
appsv1 "k8s.io/api/apps/v1"
1515
extv1beta1 "k8s.io/api/extensions/v1beta1"
16+
17+
certapi "github.com/GoogleCloudPlatform/gke-managed-certs/pkg/apis/networking.gke.io/v1beta1"
1618
)
1719

1820
func renderK8SServiceDeploymentWithSetValues(t *testing.T, setValues map[string]string) appsv1.Deployment {
@@ -50,3 +52,21 @@ func renderK8SServiceIngressWithSetValues(t *testing.T, setValues map[string]str
5052
helm.UnmarshalK8SYaml(t, out, &ingress)
5153
return ingress
5254
}
55+
56+
func renderK8SServiceManagedCertificateWithSetValues(t *testing.T, setValues map[string]string) certapi.ManagedCertificate {
57+
helmChartPath, err := filepath.Abs(filepath.Join("..", "charts", "k8s-service"))
58+
require.NoError(t, err)
59+
60+
// We make sure to pass in the linter_values.yaml values file, which we assume has all the required values defined.
61+
options := &helm.Options{
62+
ValuesFiles: []string{filepath.Join("..", "charts", "k8s-service", "linter_values.yaml")},
63+
SetValues: setValues,
64+
}
65+
// Render just the google managed certificate resource
66+
out := helm.RenderTemplate(t, options, helmChartPath, []string{"templates/gmc.yaml"})
67+
68+
// Parse the deployment and verify the preStop hook is set
69+
var cert certapi.ManagedCertificate
70+
helm.UnmarshalK8SYaml(t, out, &cert)
71+
return cert
72+
}

test/k8s_service_template_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,3 +436,42 @@ func TestK8SServiceIngressAdditionalPathsHigherPriorityNoServiceName(t *testing.
436436
assert.Equal(t, strings.ToLower(secondPath.Backend.ServiceName), "release-name-linter")
437437
assert.Equal(t, secondPath.Backend.ServicePort.StrVal, "app")
438438
}
439+
440+
// Test rendering Managed Certificate
441+
func TestK8SServiceManagedCertDomainName(t *testing.T) {
442+
t.Parallel()
443+
444+
cert := renderK8SServiceManagedCertificateWithSetValues(
445+
t,
446+
map[string]string{
447+
"google.managedCertificate.enabled": "true",
448+
"google.managedCertificate.domainName": "api.acme.io",
449+
},
450+
)
451+
452+
domains := cert.Spec.Domains
453+
assert.Equal(t, len(domains), 1)
454+
assert.Equal(t, domains[0], "api.acme.io")
455+
}
456+
457+
// Test that setting ingress.enabled = false will cause the helm template to not render the ManagedCertificate resource
458+
func TestK8SServiceManagedCertificateDefaultsDoesNotCreateManagedCertificate(t *testing.T) {
459+
t.Parallel()
460+
461+
helmChartPath, err := filepath.Abs(filepath.Join("..", "charts", "k8s-service"))
462+
require.NoError(t, err)
463+
464+
// We make sure to pass in the linter_values.yaml values file, which we assume has all the required values defined.
465+
// We then use SetValues to override all the defaults.
466+
options := &helm.Options{
467+
ValuesFiles: []string{filepath.Join("..", "charts", "k8s-service", "linter_values.yaml")},
468+
SetValues: map[string]string{},
469+
}
470+
out := helm.RenderTemplate(t, options, helmChartPath, []string{"templates/gmc.yaml"})
471+
472+
// We take the output and render it to a map to validate it is an empty yaml
473+
rendered := map[string]interface{}{}
474+
err = yaml.Unmarshal([]byte(out), &rendered)
475+
assert.NoError(t, err)
476+
assert.Equal(t, len(rendered), 0)
477+
}

0 commit comments

Comments
 (0)