Skip to content

Commit 3f0846a

Browse files
Support for Vanity Name and Bring Your Own Certificates (#85)
* Add environment variable to allow specifying lattice service endpoint * Update lattice sdk APIs to the version which contains BYOC * Update with right byoc SDK * Use 1st hostname of HTTProute as lattice customer-domain-name * Add logic to parse certARN and pass it to lattice * Postpone targetgroup/target reconcile during HTTPRoute delete (#83) * Add some examples that uses vanity name and customer own certificates * Add unit test on hostname parse logic * Add unit test for parsing certificate ARN * Fix go fmt * Add lattice-assigned-dns annotation to httproute * Add doc on how to configure custom domain name * minor update on custom domain name doc * Minor update to custom doman name doc * Add doc on BYOC certification * Add doc on BYOC * Add nil check to avoid crashing
1 parent 60dae41 commit 3f0846a

File tree

14 files changed

+526
-48
lines changed

14 files changed

+526
-48
lines changed

controllers/httproute_controller.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,13 @@ func (r *HTTPRouteReconciler) updateHTTPRouteStatus(ctx context.Context, dns str
275275
httproute.Status.RouteStatus.Parents[0].Conditions = make([]metav1.Condition, 1)
276276
httproute.Status.RouteStatus.Parents[0].Conditions[0].LastTransitionTime = eventhandlers.ZeroTransitionTime
277277
}
278+
279+
if len(httproute.ObjectMeta.Annotations) == 0 {
280+
httproute.ObjectMeta.Annotations = make(map[string]string)
281+
}
282+
283+
httproute.ObjectMeta.Annotations["application-networking.k8s.aws/lattice-assigned-domain-name"] = dns
284+
278285
httproute.Status.RouteStatus.Parents[0].ControllerName = config.LatticeGatewayControllerName
279286

280287
httproute.Status.RouteStatus.Parents[0].Conditions[0].Type = "httproute"
@@ -290,8 +297,8 @@ func (r *HTTPRouteReconciler) updateHTTPRouteStatus(ctx context.Context, dns str
290297
httproute.Status.RouteStatus.Parents[0].ParentRef.Kind = httproute.Spec.ParentRefs[0].Kind
291298
httproute.Status.RouteStatus.Parents[0].ParentRef.Name = httproute.Spec.ParentRefs[0].Name
292299

293-
if err := r.Client.Status().Patch(ctx, httproute, client.MergeFrom(httprouteOld)); err != nil {
294-
glog.V(6).Infof("updateHTTPRouteStatus: Patch() received err %v \n", err)
300+
if err := r.Client.Patch(ctx, httproute, client.MergeFrom(httprouteOld)); err != nil {
301+
glog.V(2).Infof("updateHTTPRouteStatus: Patch() received err %v \n", err)
295302
return errors.Wrapf(err, "failed to update httproute status")
296303
}
297304

docs/customer_domain_name.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Configure a Custom Domain Name for HTTPRoute
2+
Today when you create a HTTPRoute using `amazon-vpc-lattice` gatewayclass, Lattice gateway-api-controller creates a AWS VPC Lattice Service during reconciliation. And VPC Lattice generates a unique Fully Qualified Domain Name (FQDN). However, this VPC Lattice generated domain name is not easy for customers to remember and use.
3+
4+
If you'd prefer to use a custom domain name for a HTTPRoute, you can specify them in hostname field of HTTPRoute. Here is one example
5+
6+
```
7+
apiVersion: gateway.networking.k8s.io/v1alpha2
8+
kind: HTTPRoute
9+
metadata:
10+
name: review
11+
spec:
12+
hostnames:
13+
- review.my-test.com <----------- this is the custom domain name
14+
parentRefs:
15+
- name: my-hotel
16+
sectionName: http
17+
rules:
18+
- backendRefs:
19+
- name: review2
20+
kind: Service
21+
port: 8090
22+
matches:
23+
- path:
24+
type: PathPrefix
25+
value: /review2
26+
27+
```
28+
29+
## Notes
30+
31+
* You MUST have a registered domain name (e.g. `my-test.com`) in route53 and complete the `Prerequisites` mentioned in [TODO - public BYOC doc](http://dev-dsk-tnmat-1d-8836d755.us-east-1.amazon.com/mercury/build/AWSMercuryDocs/AWSMercuryDocs-3.0/AL2_x86_64/DEV.STD.PTHREAD/build/server-root/vpc-lattice/latest/ug/service-custom-domain-name.html#dns-associate-custom)
32+
33+
* In addition, you NEED to manually associate your custom domain name with your service following [TODO - public BYOC doc](http://dev-dsk-tnmat-1d-8836d755.us-east-1.amazon.com/mercury/build/AWSMercuryDocs/AWSMercuryDocs-3.0/AL2_x86_64/DEV.STD.PTHREAD/build/server-root/vpc-lattice/latest/ug/service-custom-domain-name.html#dns-associate-custom). We do have [github issue](https://github.com/aws/aws-application-networking-k8s/issues/88), an enhancement request, to automate this process

docs/https_byoc.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# HTTPS and Bring Your Own Certificte (BYOC)
2+
## Securing Traffic using HTTPS
3+
4+
Today, the HTTPRoute owner can specify all incoming traffic `MUST` use HTTPs. e.g.
5+
6+
```
7+
apiVersion: gateway.networking.k8s.io/v1alpha2
8+
kind: Gateway
9+
metadata:
10+
name: my-hotel
11+
spec:
12+
gatewayClassName: amazon-vpc-lattice
13+
listeners:
14+
- name: http
15+
protocol: HTTP
16+
port: 80
17+
- name: https <-------------- specify HTTPs listener
18+
protocol: HTTPS
19+
port: 443
20+
```
21+
22+
```
23+
apiVersion: gateway.networking.k8s.io/v1alpha2
24+
kind: HTTPRoute
25+
metadata:
26+
name: rates
27+
spec:
28+
parentRefs:
29+
- name: my-hotel
30+
sectionName: http
31+
- name: my-hotel
32+
sectionName: https <--- specify all traffic MUST use HTTPs
33+
rules:
34+
- backendRefs:
35+
- name: parking
36+
kind: Service
37+
port: 8090
38+
matches:
39+
- path:
40+
type: PathPrefix
41+
value: /parking
42+
- backendRefs:
43+
- name: review
44+
kind: Service
45+
port: 8090
46+
matches:
47+
- path:
48+
type: PathPrefix
49+
value: /review
50+
```
51+
52+
In this case, VPC Lattice service will automatically generate a managed ACM certificate and use it for encryting client to service traffic.
53+
54+
## Bring Your Own Certificate (BYOC)
55+
56+
If customer desires to use custom domain name along with their own certificate, they can do following:
57+
* follow [TODO Bring Your Own Certicate DOC](http://dev-dsk-tnmat-1d-8836d755.us-east-1.amazon.com/mercury/build/AWSMercuryDocs/AWSMercuryDocs-3.0/AL2_x86_64/DEV.STD.PTHREAD/build/server-root/vpc-lattice/latest/ug/service-byoc.html), and get ACM certificate ARN
58+
* specify certificate ARN
59+
60+
```
61+
apiVersion: gateway.networking.k8s.io/v1alpha2
62+
kind: Gateway
63+
metadata:
64+
name: my-hotel
65+
spec:
66+
gatewayClassName: amazon-vpc-lattice
67+
listeners:
68+
- name: http
69+
protocol: HTTP
70+
port: 80
71+
- name: https
72+
protocol: HTTPS
73+
port: 443
74+
- name: rates-with-custom-cert
75+
protocol: HTTPS
76+
port: 443
77+
tls:
78+
mode: Terminate
79+
options:
80+
application-networking.k8s.aws/certificate-arn: arn:aws:acm:us-west-2:<account>:certificate/4555204d-07e1-43f0-a533-d02750f41545
81+
```
82+
83+
* associate HTTPRoute to this
84+
85+
```
86+
apiVersion: gateway.networking.k8s.io/v1alpha2
87+
kind: HTTPRoute
88+
metadata:
89+
name: rates
90+
spec:
91+
parentRefs:
92+
- name: my-hotel
93+
sectionName: http
94+
- name: my-hotel
95+
sectionName: rates-with-custom-cert <-----using custom defined certification
96+
rules:
97+
- backendRefs:
98+
- name: parking
99+
kind: Service
100+
port: 8090
101+
matches:
102+
- path:
103+
type: PathPrefix
104+
value: /parking
105+
- backendRefs:
106+
- name: review
107+
kind: Service
108+
port: 8090
109+
matches:
110+
- path:
111+
type: PathPrefix
112+
value: /review
113+
```
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: gateway.networking.k8s.io/v1alpha2
2+
kind: HTTPRoute
3+
metadata:
4+
name: review
5+
spec:
6+
hostnames:
7+
- review.my-test.com
8+
parentRefs:
9+
- name: my-hotel
10+
sectionName: http
11+
rules:
12+
- backendRefs:
13+
- name: review2
14+
kind: Service
15+
port: 8090
16+
matches:
17+
- path:
18+
type: PathPrefix
19+
value: /review2

examples/my-hotel-gateway-tls.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apiVersion: gateway.networking.k8s.io/v1alpha2
2+
kind: Gateway
3+
metadata:
4+
name: my-hotel
5+
spec:
6+
gatewayClassName: amazon-vpc-lattice
7+
listeners:
8+
- name: http
9+
protocol: HTTP
10+
port: 80
11+
- name: https
12+
protocol: HTTPS
13+
port: 443
14+
- name: tls-with-customer-cert
15+
protocol: HTTPS
16+
port: 443
17+
tls:
18+
mode: Terminate
19+
options:
20+
application-networking.k8s.aws/certificate-arn: arn:aws:acm:us-west-2:<account>:certificate/4555204d-07e1-43f0-a533-d02750f41545
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: gateway.networking.k8s.io/v1alpha2
2+
kind: HTTPRoute
3+
metadata:
4+
name: review
5+
spec:
6+
hostnames:
7+
- review.my-test.com
8+
parentRefs:
9+
- name: my-hotel
10+
sectionName: tls-with-customer-cert
11+
rules:
12+
- backendRefs:
13+
- name: review1
14+
kind: Service
15+
port: 8090
16+
matches:
17+
- path:
18+
type: PathPrefix
19+
value: /review1

pkg/deploy/lattice/service_manager.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ func (s *defaultServiceManager) Create(ctx context.Context, service *latticemode
7676
Name: &svcName,
7777
Tags: nil,
7878
}
79+
80+
if len(service.Spec.CustomerDomainName) > 0 {
81+
serviceInput.CustomDomainName = &service.Spec.CustomerDomainName
82+
}
83+
84+
if len(service.Spec.CustomerCertARN) > 0 {
85+
serviceInput.SetCertificateArn(service.Spec.CustomerCertARN)
86+
}
7987
latticeSess := s.cloud.Lattice()
8088
resp, err := latticeSess.CreateServiceWithContext(ctx, &serviceInput)
8189
glog.V(2).Infof("CreateServiceWithContext >>>> req %v resp %v err %v\n", serviceInput, resp, err)
@@ -92,6 +100,22 @@ func (s *defaultServiceManager) Create(ctx context.Context, service *latticemode
92100
if serviceSummary.DnsEntry != nil {
93101
serviceDNS = aws.StringValue(serviceSummary.DnsEntry.DomainName)
94102
}
103+
104+
if len(service.Spec.CustomerCertARN) > 0 {
105+
serviceUpdateInput := vpclattice.UpdateServiceInput{
106+
ServiceIdentifier: serviceSummary.Id,
107+
CertificateArn: aws.String(service.Spec.CustomerCertARN),
108+
}
109+
110+
latticeSess := s.cloud.Lattice()
111+
resp, err := latticeSess.UpdateServiceWithContext(ctx, &serviceUpdateInput)
112+
glog.V(2).Infof("UpdateServiceWithContext >>>> req %v resp %v err %v\n", serviceUpdateInput, resp, err)
113+
if err != nil {
114+
glog.V(6).Infoln("fail to update service")
115+
return latticemodel.ServiceStatus{ServiceARN: "", ServiceID: ""}, err
116+
}
117+
118+
}
95119
isServiceAssociatedWithServiceNetwork, serviceDNS, err = s.isServiceAssociatedWithServiceNetwork(ctx, serviceID, serviceNetwork.ID)
96120
if err != nil {
97121
return latticemodel.ServiceStatus{ServiceARN: "", ServiceID: ""}, err

pkg/gateway/model_build_lattice_service.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,18 @@ func (t *latticeServiceModelBuildTask) buildLatticeService(ctx context.Context)
125125
ServiceNetworkName: string(t.httpRoute.Spec.ParentRefs[0].Name),
126126
}
127127

128+
if len(t.httpRoute.Spec.Hostnames) > 0 {
129+
// The 1st hostname will be used as lattice customer-domain-name
130+
spec.CustomerDomainName = string(t.httpRoute.Spec.Hostnames[0])
131+
132+
glog.V(2).Infof("Setting customer-domain-name: %v for httpRoute %v-%v",
133+
spec.CustomerDomainName, t.httpRoute.Name, t.httpRoute.Namespace)
134+
} else {
135+
glog.V(2).Infof("No customter-domain-name for httproute :%v-%v",
136+
t.httpRoute.Name, t.httpRoute.Namespace)
137+
spec.CustomerDomainName = ""
138+
}
139+
128140
if t.httpRoute.DeletionTimestamp.IsZero() {
129141
spec.IsDeleted = false
130142
} else {

pkg/gateway/model_build_lattice_service_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,32 @@ func Test_LatticeServiceModelBuild(t *testing.T) {
5656
wantName string
5757
wantIsDeleted bool
5858
}{
59+
{
60+
name: "Add LatticeService with hostname",
61+
httpRoute: &v1alpha2.HTTPRoute{
62+
ObjectMeta: metav1.ObjectMeta{
63+
Name: "service1",
64+
},
65+
Spec: v1alpha2.HTTPRouteSpec{
66+
CommonRouteSpec: v1alpha2.CommonRouteSpec{
67+
ParentRefs: []v1alpha2.ParentRef{
68+
{
69+
Name: "gateway1",
70+
},
71+
},
72+
},
73+
Hostnames: []v1alpha2.Hostname{
74+
"test1.test.com",
75+
"test2.test.com",
76+
},
77+
},
78+
},
79+
80+
wantError: nil,
81+
wantName: "service1",
82+
wantIsDeleted: false,
83+
wantErrIsNil: true,
84+
},
5985
{
6086
name: "Add LatticeService",
6187
httpRoute: &v1alpha2.HTTPRoute{
@@ -159,6 +185,12 @@ func Test_LatticeServiceModelBuild(t *testing.T) {
159185
assert.Equal(t, false, task.latticeService.Spec.IsDeleted)
160186
assert.Equal(t, tt.httpRoute.Name, task.latticeService.Spec.Name)
161187
assert.Equal(t, tt.httpRoute.Namespace, task.latticeService.Spec.Namespace)
188+
189+
if len(tt.httpRoute.Spec.Hostnames) > 0 {
190+
assert.Equal(t, string(tt.httpRoute.Spec.Hostnames[0]), task.latticeService.Spec.CustomerDomainName)
191+
} else {
192+
assert.Equal(t, "", task.latticeService.Spec.CustomerDomainName)
193+
}
162194
}
163195

164196
if tt.wantErrIsNil {

0 commit comments

Comments
 (0)