Skip to content

Commit

Permalink
Support for Vanity Name and Bring Your Own Certificates (#85)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
liwenwu-amazon authored Feb 13, 2023
1 parent 60dae41 commit 3f0846a
Show file tree
Hide file tree
Showing 14 changed files with 526 additions and 48 deletions.
11 changes: 9 additions & 2 deletions controllers/httproute_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ func (r *HTTPRouteReconciler) updateHTTPRouteStatus(ctx context.Context, dns str
httproute.Status.RouteStatus.Parents[0].Conditions = make([]metav1.Condition, 1)
httproute.Status.RouteStatus.Parents[0].Conditions[0].LastTransitionTime = eventhandlers.ZeroTransitionTime
}

if len(httproute.ObjectMeta.Annotations) == 0 {
httproute.ObjectMeta.Annotations = make(map[string]string)
}

httproute.ObjectMeta.Annotations["application-networking.k8s.aws/lattice-assigned-domain-name"] = dns

httproute.Status.RouteStatus.Parents[0].ControllerName = config.LatticeGatewayControllerName

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

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

Expand Down
33 changes: 33 additions & 0 deletions docs/customer_domain_name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Configure a Custom Domain Name for HTTPRoute
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.

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

```
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
name: review
spec:
hostnames:
- review.my-test.com <----------- this is the custom domain name
parentRefs:
- name: my-hotel
sectionName: http
rules:
- backendRefs:
- name: review2
kind: Service
port: 8090
matches:
- path:
type: PathPrefix
value: /review2
```

## Notes

* 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)

* 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
113 changes: 113 additions & 0 deletions docs/https_byoc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# HTTPS and Bring Your Own Certificte (BYOC)
## Securing Traffic using HTTPS

Today, the HTTPRoute owner can specify all incoming traffic `MUST` use HTTPs. e.g.

```
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: my-hotel
spec:
gatewayClassName: amazon-vpc-lattice
listeners:
- name: http
protocol: HTTP
port: 80
- name: https <-------------- specify HTTPs listener
protocol: HTTPS
port: 443
```

```
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
name: rates
spec:
parentRefs:
- name: my-hotel
sectionName: http
- name: my-hotel
sectionName: https <--- specify all traffic MUST use HTTPs
rules:
- backendRefs:
- name: parking
kind: Service
port: 8090
matches:
- path:
type: PathPrefix
value: /parking
- backendRefs:
- name: review
kind: Service
port: 8090
matches:
- path:
type: PathPrefix
value: /review
```

In this case, VPC Lattice service will automatically generate a managed ACM certificate and use it for encryting client to service traffic.

## Bring Your Own Certificate (BYOC)

If customer desires to use custom domain name along with their own certificate, they can do following:
* 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
* specify certificate ARN

```
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: my-hotel
spec:
gatewayClassName: amazon-vpc-lattice
listeners:
- name: http
protocol: HTTP
port: 80
- name: https
protocol: HTTPS
port: 443
- name: rates-with-custom-cert
protocol: HTTPS
port: 443
tls:
mode: Terminate
options:
application-networking.k8s.aws/certificate-arn: arn:aws:acm:us-west-2:<account>:certificate/4555204d-07e1-43f0-a533-d02750f41545
```

* associate HTTPRoute to this

```
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
name: rates
spec:
parentRefs:
- name: my-hotel
sectionName: http
- name: my-hotel
sectionName: rates-with-custom-cert <-----using custom defined certification
rules:
- backendRefs:
- name: parking
kind: Service
port: 8090
matches:
- path:
type: PathPrefix
value: /parking
- backendRefs:
- name: review
kind: Service
port: 8090
matches:
- path:
type: PathPrefix
value: /review
```
19 changes: 19 additions & 0 deletions examples/http-route-use-vanity-name.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
name: review
spec:
hostnames:
- review.my-test.com
parentRefs:
- name: my-hotel
sectionName: http
rules:
- backendRefs:
- name: review2
kind: Service
port: 8090
matches:
- path:
type: PathPrefix
value: /review2
20 changes: 20 additions & 0 deletions examples/my-hotel-gateway-tls.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: my-hotel
spec:
gatewayClassName: amazon-vpc-lattice
listeners:
- name: http
protocol: HTTP
port: 80
- name: https
protocol: HTTPS
port: 443
- name: tls-with-customer-cert
protocol: HTTPS
port: 443
tls:
mode: Terminate
options:
application-networking.k8s.aws/certificate-arn: arn:aws:acm:us-west-2:<account>:certificate/4555204d-07e1-43f0-a533-d02750f41545
19 changes: 19 additions & 0 deletions examples/tls-route-with-own-cert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
name: review
spec:
hostnames:
- review.my-test.com
parentRefs:
- name: my-hotel
sectionName: tls-with-customer-cert
rules:
- backendRefs:
- name: review1
kind: Service
port: 8090
matches:
- path:
type: PathPrefix
value: /review1
24 changes: 24 additions & 0 deletions pkg/deploy/lattice/service_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ func (s *defaultServiceManager) Create(ctx context.Context, service *latticemode
Name: &svcName,
Tags: nil,
}

if len(service.Spec.CustomerDomainName) > 0 {
serviceInput.CustomDomainName = &service.Spec.CustomerDomainName
}

if len(service.Spec.CustomerCertARN) > 0 {
serviceInput.SetCertificateArn(service.Spec.CustomerCertARN)
}
latticeSess := s.cloud.Lattice()
resp, err := latticeSess.CreateServiceWithContext(ctx, &serviceInput)
glog.V(2).Infof("CreateServiceWithContext >>>> req %v resp %v err %v\n", serviceInput, resp, err)
Expand All @@ -92,6 +100,22 @@ func (s *defaultServiceManager) Create(ctx context.Context, service *latticemode
if serviceSummary.DnsEntry != nil {
serviceDNS = aws.StringValue(serviceSummary.DnsEntry.DomainName)
}

if len(service.Spec.CustomerCertARN) > 0 {
serviceUpdateInput := vpclattice.UpdateServiceInput{
ServiceIdentifier: serviceSummary.Id,
CertificateArn: aws.String(service.Spec.CustomerCertARN),
}

latticeSess := s.cloud.Lattice()
resp, err := latticeSess.UpdateServiceWithContext(ctx, &serviceUpdateInput)
glog.V(2).Infof("UpdateServiceWithContext >>>> req %v resp %v err %v\n", serviceUpdateInput, resp, err)
if err != nil {
glog.V(6).Infoln("fail to update service")
return latticemodel.ServiceStatus{ServiceARN: "", ServiceID: ""}, err
}

}
isServiceAssociatedWithServiceNetwork, serviceDNS, err = s.isServiceAssociatedWithServiceNetwork(ctx, serviceID, serviceNetwork.ID)
if err != nil {
return latticemodel.ServiceStatus{ServiceARN: "", ServiceID: ""}, err
Expand Down
12 changes: 12 additions & 0 deletions pkg/gateway/model_build_lattice_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,18 @@ func (t *latticeServiceModelBuildTask) buildLatticeService(ctx context.Context)
ServiceNetworkName: string(t.httpRoute.Spec.ParentRefs[0].Name),
}

if len(t.httpRoute.Spec.Hostnames) > 0 {
// The 1st hostname will be used as lattice customer-domain-name
spec.CustomerDomainName = string(t.httpRoute.Spec.Hostnames[0])

glog.V(2).Infof("Setting customer-domain-name: %v for httpRoute %v-%v",
spec.CustomerDomainName, t.httpRoute.Name, t.httpRoute.Namespace)
} else {
glog.V(2).Infof("No customter-domain-name for httproute :%v-%v",
t.httpRoute.Name, t.httpRoute.Namespace)
spec.CustomerDomainName = ""
}

if t.httpRoute.DeletionTimestamp.IsZero() {
spec.IsDeleted = false
} else {
Expand Down
32 changes: 32 additions & 0 deletions pkg/gateway/model_build_lattice_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,32 @@ func Test_LatticeServiceModelBuild(t *testing.T) {
wantName string
wantIsDeleted bool
}{
{
name: "Add LatticeService with hostname",
httpRoute: &v1alpha2.HTTPRoute{
ObjectMeta: metav1.ObjectMeta{
Name: "service1",
},
Spec: v1alpha2.HTTPRouteSpec{
CommonRouteSpec: v1alpha2.CommonRouteSpec{
ParentRefs: []v1alpha2.ParentRef{
{
Name: "gateway1",
},
},
},
Hostnames: []v1alpha2.Hostname{
"test1.test.com",
"test2.test.com",
},
},
},

wantError: nil,
wantName: "service1",
wantIsDeleted: false,
wantErrIsNil: true,
},
{
name: "Add LatticeService",
httpRoute: &v1alpha2.HTTPRoute{
Expand Down Expand Up @@ -159,6 +185,12 @@ func Test_LatticeServiceModelBuild(t *testing.T) {
assert.Equal(t, false, task.latticeService.Spec.IsDeleted)
assert.Equal(t, tt.httpRoute.Name, task.latticeService.Spec.Name)
assert.Equal(t, tt.httpRoute.Namespace, task.latticeService.Spec.Namespace)

if len(tt.httpRoute.Spec.Hostnames) > 0 {
assert.Equal(t, string(tt.httpRoute.Spec.Hostnames[0]), task.latticeService.Spec.CustomerDomainName)
} else {
assert.Equal(t, "", task.latticeService.Spec.CustomerDomainName)
}
}

if tt.wantErrIsNil {
Expand Down
Loading

0 comments on commit 3f0846a

Please sign in to comment.