├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app ├── Dockerfile ├── Makefile ├── default.conf ├── entrypoint.sh ├── go.mod ├── go.sum ├── html │ ├── Arch_Amazon-Elastic-Container-Kubernetes_64@5x.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── index.html.tmpl │ └── site.webmanifest └── main.go ├── deployment.yaml ├── ingresses.yaml ├── nlb-services.yaml ├── policy.json └── security-group-policy.yaml /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-eks-sample-http-service/10f2dab309c230794ac9838935c351983f2db30c/.gitignore -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Sample: Simple Go Web Server for Amazon EKS 2 | ## Overview 3 | 4 | This repository contains a webserver written in Go. Its only function is to 5 | return a web page showing some interesting data about the Kubernetes Pod and EC2 6 | instance on which it runs, along with remote IP address information. 7 | 8 | This server can be used to illustrate the differences in behavior when you 9 | choose Instances versus IP addresses in a Network or Application Load Balancer's 10 | Target Group type. It can also be used to show the impact of enabling the Proxy 11 | v2 Protocol on Network Load Balancers. 12 | 13 | The server listens on ports 8080 and 9080. Port 9080 requires the [Proxy v2 14 | protocol supported by AWS Network Load 15 | Balancers](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#proxy-protocol) 16 | to provide client IP address information. Port 8080 is for use without the Proxy 17 | protocol. 18 | 19 | ## Prerequisites 20 | 21 | You'll need to create an IAM policy as follows. The policy only allows the webserver 22 | to describe EC2 network interfaces: 23 | 24 | ```sh 25 | POLICY_ARN=$(aws iam create-policy \ 26 | --policy-name EKSLoadBalancerDemo \ 27 | --policy-document file://policy.json \ 28 | --query 'Policy.Arn' --output text) 29 | ``` 30 | 31 | Then, you'll need to create a Service Account in your EKS cluster. This service 32 | is called `aws-lb-demo` in the `default` namespace. The podspec located in 33 | `deployment.yaml` refers to this name and namespace. You can change these if you 34 | like, but you'll need to make sure the podspec is also changed if you do. 35 | 36 | ```sh 37 | eksctl create iamserviceaccount \ 38 | --cluster $CLUSTER \ 39 | --attach-policy-arn $POLICY_ARN \ 40 | --namespace default \ 41 | --name aws-lb-demo \ 42 | --override-existing-serviceaccounts \ 43 | --approve 44 | ``` 45 | 46 | ## Other files 47 | 48 | The `deployment.yaml` file has a couple of application deployment manifests in 49 | it. `ingresses.yaml` contains some service and ingress manifests. Finally, the 50 | `nlb-services.yaml` file defines some Load Balancer services that create Network 51 | Load Balancers. It creates multiple Load Balancers via both the legacy 52 | in-tree NLB controller and the AWS Load Balancer v2 controller. 53 | 54 | ## Warnings 55 | 56 | This software is unsupported and not for production use. It is for demonstration 57 | purposes only. 58 | 59 | Use of this software may cause you to incur AWS charges for the resources 60 | created. Charges are the sole responsibility of the customer. We encourage you to 61 | destroy these resources after you have finished using them. 62 | -------------------------------------------------------------------------------- /app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/docker/library/golang:1.20.7 AS build 2 | 3 | ENV GOPROXY=direct CGO_ENABLED=0 4 | 5 | RUN mkdir /build 6 | COPY go.mod go.sum main.go /build/ 7 | WORKDIR /build 8 | RUN go mod download 9 | RUN go build -o server 10 | 11 | FROM scratch 12 | COPY --from=build /build/server /server 13 | COPY --from=build /etc/ssl/certs/ /etc/ssl/certs/ 14 | COPY html/ /html/ 15 | 16 | # Standard HTTP port 17 | EXPOSE 8080 18 | # HTTP wrapped in PROXY protocol 19 | EXPOSE 9080 20 | 21 | USER 101 22 | 23 | ENTRYPOINT ["/server"] 24 | -------------------------------------------------------------------------------- /app/Makefile: -------------------------------------------------------------------------------- 1 | ECR_ENDPOINT := 749049578452.dkr.ecr.us-west-2.amazonaws.com 2 | ECR_REPO := $(ECR_ENDPOINT)/eks-demo-app 3 | 4 | .PHONY: push 5 | push: build 6 | aws ecr get-login-password | docker login -u AWS --password-stdin $(ECR_ENDPOINT) 7 | docker push $(ECR_REPO) 8 | 9 | .PHONY: build 10 | build: 11 | docker build -t $(ECR_REPO) . 12 | -------------------------------------------------------------------------------- /app/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8080; 3 | listen [::]:8080; 4 | 5 | listen 9080 proxy_protocol; 6 | listen [::]:9080 proxy_protocol; 7 | 8 | server_name localhost; 9 | 10 | real_ip_header proxy_protocol; 11 | # Assume RFC1918 address spaces are VPC-local and trustworthy 12 | set_real_ip_from 10.0.0.0/8; 13 | set_real_ip_from 192.168.0.0/16; 14 | 15 | 16 | location / { 17 | root /usr/share/nginx/html; 18 | try_files $uri /index.html; 19 | ssi on; 20 | } 21 | 22 | location /run/ { 23 | internal; 24 | alias /run/; 25 | } 26 | 27 | error_page 500 502 503 504 /50x.html; 28 | location = /50x.html { 29 | root /usr/share/nginx/html; 30 | } 31 | } 32 | 33 | # server { 34 | # listen 9080 proxy_protocol; 35 | # listen [::]:9080 proxy_protocol; 36 | 37 | # error_log /dev/stderr debug; 38 | 39 | # real_ip_header proxy_protocol; 40 | # # Assume RFC1918 address spaces are VPC-local and trustworthy 41 | # set_real_ip_from 10.0.0.0/8; 42 | # set_real_ip_from 192.168.0.0/16; 43 | 44 | # server_name localhost; 45 | 46 | # log_subrequest on; 47 | 48 | # location / { 49 | # root /usr/share/nginx/html; 50 | # try_files $uri index.html; 51 | # ssi on; 52 | # } 53 | 54 | # location /run/ { 55 | # internal; 56 | # alias /run/; 57 | # } 58 | 59 | # error_page 500 502 503 504 /50x.html; 60 | # location = /50x.html { 61 | # root /usr/share/nginx/html; 62 | # } 63 | # } -------------------------------------------------------------------------------- /app/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | 5 | mkdir -p /var/cache/nginx 6 | 7 | get_metadata() { 8 | metadata_url="http://169.254.169.254/latest/meta-data/$1"; shift 9 | file="$1"; shift 10 | 11 | if ! curl -sf -o "$file" "$metadata_url"; then 12 | if [ -z "$TOKEN" ]; then 13 | TOKEN=`curl -sf -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` 14 | fi 15 | curl -H "X-aws-ec2-metadata-token: $TOKEN" -sSf -o "$file" "$metadata_url" 16 | fi 17 | } 18 | 19 | # /run must be mounted read-write via tmpfs 20 | get_metadata instance-id /run/instance-id.txt 21 | get_metadata placement/availability-zone /run/availability-zone.txt 22 | 23 | -------------------------------------------------------------------------------- /app/go.mod: -------------------------------------------------------------------------------- 1 | module aws-lb-v2-demo 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/aws/aws-sdk-go v1.44.316 7 | github.com/pires/go-proxyproto v0.7.0 8 | github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a 9 | ) 10 | 11 | require ( 12 | github.com/jmespath/go-jmespath v0.4.0 // indirect 13 | github.com/stretchr/testify v1.6.1 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /app/go.sum: -------------------------------------------------------------------------------- 1 | github.com/aws/aws-sdk-go v1.44.316 h1:UC3alCEyzj2XU13ZFGIOHW3yjCNLGTIGVauyetl9fwE= 2 | github.com/aws/aws-sdk-go v1.44.316/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= 3 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 6 | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= 7 | github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= 8 | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= 9 | github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= 10 | github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= 11 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 12 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 13 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 14 | github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a h1:iLcLb5Fwwz7g/DLK89F+uQBDeAhHhwdzB5fSlVdhGcM= 15 | github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0= 16 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 17 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 18 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 19 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 20 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 21 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 22 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 23 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 24 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 25 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 26 | golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= 27 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 28 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 29 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 30 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 31 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 32 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 33 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 34 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 35 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 36 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 37 | golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 38 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 39 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 40 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 41 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 42 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 43 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 44 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 45 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 46 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 47 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 48 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 49 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 50 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 51 | -------------------------------------------------------------------------------- /app/html/Arch_Amazon-Elastic-Container-Kubernetes_64@5x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-eks-sample-http-service/10f2dab309c230794ac9838935c351983f2db30c/app/html/Arch_Amazon-Elastic-Container-Kubernetes_64@5x.png -------------------------------------------------------------------------------- /app/html/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-eks-sample-http-service/10f2dab309c230794ac9838935c351983f2db30c/app/html/android-chrome-192x192.png -------------------------------------------------------------------------------- /app/html/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-eks-sample-http-service/10f2dab309c230794ac9838935c351983f2db30c/app/html/android-chrome-512x512.png -------------------------------------------------------------------------------- /app/html/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-eks-sample-http-service/10f2dab309c230794ac9838935c351983f2db30c/app/html/apple-touch-icon.png -------------------------------------------------------------------------------- /app/html/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-eks-sample-http-service/10f2dab309c230794ac9838935c351983f2db30c/app/html/favicon-16x16.png -------------------------------------------------------------------------------- /app/html/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-eks-sample-http-service/10f2dab309c230794ac9838935c351983f2db30c/app/html/favicon-32x32.png -------------------------------------------------------------------------------- /app/html/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-eks-sample-http-service/10f2dab309c230794ac9838935c351983f2db30c/app/html/favicon.ico -------------------------------------------------------------------------------- /app/html/index.html.tmpl: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 |App label: {{.AppLabel}}
32 |Requested URI: {{.URL.Path}}
33 |This application is being run on instance ID {{.Identity.InstanceID}} 34 | in Availability Zone {{.Identity.AvailabilityZone}}.
35 |Pod: {{.PodName}} in namespace {{.PodNamespace}}.
36 |Your client IP address appears to be {{.RemoteAddr}} ({{.RemoteType}}){{if ne .RemoteAddr .PeerAddr}} (via {{.PeerAddr}} ({{.PeerType}})){{end}} 37 | (PROXY protocol is {{if .ProxyProtocolEnabled}}enabled{{else}}disabled{{end}}).
38 | 39 | 40 | -------------------------------------------------------------------------------- /app/html/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /app/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "html/template" 6 | "io" 7 | "log" 8 | "net" 9 | "net/http" 10 | "net/url" 11 | "os" 12 | 13 | "github.com/aws/aws-sdk-go/aws" 14 | "github.com/aws/aws-sdk-go/aws/ec2metadata" 15 | "github.com/aws/aws-sdk-go/aws/session" 16 | "github.com/aws/aws-sdk-go/service/ec2" 17 | "github.com/pires/go-proxyproto" 18 | "github.com/sebest/xff" 19 | ) 20 | 21 | const ( 22 | docroot = "html" 23 | ) 24 | 25 | type handler struct { 26 | Identity ec2metadata.EC2InstanceIdentityDocument 27 | PodName string 28 | PodNamespace string 29 | AppLabel string 30 | ProxyProtocolEnabled bool 31 | } 32 | 33 | type requestInfo struct { 34 | *handler 35 | URL *url.URL 36 | PeerAddr string 37 | RemoteAddr string 38 | PeerType string 39 | RemoteType string 40 | ServerPort string 41 | } 42 | 43 | func maybeServeLocalFile(w http.ResponseWriter, r *http.Request) (bool, error) { 44 | path := docroot + r.URL.Path 45 | stat, err := os.Stat(path) 46 | if err != nil { 47 | if patherr, ok := err.(*os.PathError); ok && os.IsNotExist(patherr) { 48 | return false, nil 49 | } 50 | return false, err 51 | } 52 | if stat.IsDir() { 53 | return false, nil 54 | } 55 | f, err := os.Open(path) 56 | defer f.Close() 57 | 58 | if err != nil { 59 | return false, err 60 | } 61 | _, err = io.Copy(w, f) 62 | return true, err 63 | } 64 | 65 | func getRemoteType(region, addr string) (string, error) { 66 | sess := session.Must(session.NewSession(&aws.Config{ 67 | Region: aws.String(region), 68 | })) 69 | client := ec2.New(sess) 70 | output, err := client.DescribeNetworkInterfaces(&ec2.DescribeNetworkInterfacesInput{ 71 | Filters: []*ec2.Filter{ 72 | { 73 | Name: aws.String("addresses.private-ip-address"), 74 | Values: aws.StringSlice([]string{addr}), 75 | }, 76 | }, 77 | }) 78 | if err != nil { 79 | return "", err 80 | } 81 | if len(output.NetworkInterfaces) == 0 { 82 | return "Non-VPC IP", nil 83 | } 84 | switch aws.StringValue(output.NetworkInterfaces[0].InterfaceType) { 85 | case "interface": 86 | instanceID := aws.StringValue(output.NetworkInterfaces[0].Attachment.InstanceId) 87 | if len(instanceID) >= 2 && instanceID[0:2] == "i-" { 88 | return "Instance ID " + instanceID, nil 89 | } 90 | description := aws.StringValue(output.NetworkInterfaces[0].Description) 91 | if len(description) >= 7 && description[0:7] == "ELB app" { 92 | return "Application load balancer", nil 93 | } 94 | case "network_load_balancer": 95 | return "Network Load Balancer", nil 96 | } 97 | return "Unknown", nil 98 | } 99 | 100 | func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 101 | fmt.Printf("Requested: %v\n", r.URL) 102 | done, err := maybeServeLocalFile(w, r) 103 | if err != nil { 104 | fmt.Println(err) 105 | return 106 | } 107 | if done { 108 | return 109 | } 110 | 111 | peerAddr, _, _ := net.SplitHostPort(r.RemoteAddr) 112 | peerType, err := getRemoteType(h.Identity.Region, peerAddr) 113 | if err != nil { 114 | fmt.Println(err) 115 | return 116 | } 117 | 118 | remoteAddr, _, _ := net.SplitHostPort(xff.GetRemoteAddr(r)) 119 | remoteType, err := getRemoteType(h.Identity.Region, remoteAddr) 120 | if err != nil { 121 | fmt.Println(err) 122 | return 123 | } 124 | 125 | i := requestInfo{ 126 | handler: h, 127 | URL: r.URL, 128 | PeerAddr: peerAddr, 129 | PeerType: peerType, 130 | RemoteAddr: remoteAddr, 131 | RemoteType: remoteType, 132 | } 133 | 134 | r.Header.Get("X-Forwarded-For") 135 | 136 | localAddr := r.Context().Value(http.LocalAddrContextKey).(net.Addr).String() 137 | _, port, _ := net.SplitHostPort(localAddr) 138 | i.ServerPort = port 139 | 140 | t, _ := template.ParseFiles("html/index.html.tmpl") 141 | err = t.Execute(w, i) 142 | if err != nil { 143 | fmt.Println(err) 144 | } 145 | } 146 | 147 | func main() { 148 | sess := session.Must(session.NewSession()) 149 | m := ec2metadata.New(sess) 150 | identity, err := m.GetInstanceIdentityDocument() 151 | if err != nil { 152 | log.Fatal(err) 153 | } 154 | 155 | go func() { 156 | h := &handler{ 157 | Identity: identity, 158 | PodName: os.Getenv("POD_NAME"), 159 | PodNamespace: os.Getenv("POD_NAMESPACE"), 160 | AppLabel: os.Getenv("APP_NAME"), 161 | } 162 | 163 | listenAddr := ":8080" 164 | 165 | mux := http.NewServeMux() 166 | mux.Handle("/", h) 167 | fmt.Printf("Listening on %s\n", listenAddr) 168 | log.Fatal(http.ListenAndServe(listenAddr, mux)) 169 | }() 170 | go func() { 171 | h := &handler{ 172 | Identity: identity, 173 | PodName: os.Getenv("POD_NAME"), 174 | PodNamespace: os.Getenv("POD_NAMESPACE"), 175 | AppLabel: os.Getenv("APP_NAME"), 176 | ProxyProtocolEnabled: true, 177 | } 178 | listenAddr := ":9080" 179 | 180 | l, err := net.Listen("tcp", listenAddr) 181 | if err != nil { 182 | log.Fatal(err) 183 | } 184 | 185 | proxyListener := &proxyproto.Listener{ 186 | Listener: l, 187 | Policy: proxyproto.MustStrictWhiteListPolicy([]string{ 188 | "10.0.0.0/8", 189 | "192.168.0.0/16", 190 | }), 191 | } 192 | defer proxyListener.Close() 193 | 194 | mux := http.NewServeMux() 195 | mux.Handle("/", h) 196 | fmt.Printf("Listening on %s\n", listenAddr) 197 | log.Fatal(http.Serve(proxyListener, mux)) 198 | }() 199 | select {} 200 | } 201 | -------------------------------------------------------------------------------- /deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | app: aws-lb-demo-frontend 6 | name: aws-lb-demo-frontend 7 | spec: 8 | replicas: 2 9 | selector: 10 | matchLabels: 11 | app: aws-lb-demo-frontend 12 | strategy: {} 13 | template: 14 | metadata: 15 | labels: 16 | app: aws-lb-demo-frontend 17 | spec: 18 | serviceAccountName: aws-lb-demo 19 | # Required to read AWS account token 20 | securityContext: 21 | fsGroup: 101 22 | volumes: 23 | - name: run 24 | emptyDir: 25 | medium: Memory 26 | - name: cache 27 | emptyDir: 28 | medium: Memory 29 | containers: 30 | - image: 749049578452.dkr.ecr.us-west-2.amazonaws.com/eks-demo-app:latest 31 | name: webserver 32 | resources: 33 | requests: 34 | cpu: "100m" 35 | memory: "128Mi" 36 | volumeMounts: 37 | - mountPath: /run 38 | name: run 39 | - mountPath: /var/cache 40 | name: cache 41 | env: 42 | - name: POD_NAME 43 | valueFrom: 44 | fieldRef: 45 | fieldPath: metadata.name 46 | - name: POD_NAMESPACE 47 | valueFrom: 48 | fieldRef: 49 | fieldPath: metadata.namespace 50 | - name: APP_NAME 51 | valueFrom: 52 | fieldRef: 53 | fieldPath: metadata.labels['app'] 54 | ports: 55 | - containerPort: 8080 56 | protocol: TCP 57 | - containerPort: 9080 # PROXY protocol 58 | protocol: TCP 59 | readinessProbe: 60 | httpGet: 61 | path: / 62 | port: 8080 63 | livenessProbe: 64 | httpGet: 65 | path: / 66 | port: 8080 67 | securityContext: 68 | readOnlyRootFilesystem: true 69 | allowPrivilegeEscalation: false 70 | runAsNonRoot: true 71 | runAsUser: 101 72 | --- 73 | apiVersion: apps/v1 74 | kind: Deployment 75 | metadata: 76 | labels: 77 | app: aws-lb-demo-backend 78 | name: aws-lb-demo-backend 79 | spec: 80 | replicas: 2 81 | selector: 82 | matchLabels: 83 | app: aws-lb-demo-backend 84 | strategy: {} 85 | template: 86 | metadata: 87 | labels: 88 | app: aws-lb-demo-backend 89 | spec: 90 | serviceAccountName: aws-lb-demo 91 | # Required to read AWS account token 92 | securityContext: 93 | fsGroup: 101 94 | volumes: 95 | - name: run 96 | emptyDir: 97 | medium: Memory 98 | - name: cache 99 | emptyDir: 100 | medium: Memory 101 | containers: 102 | - image: 749049578452.dkr.ecr.us-west-2.amazonaws.com/eks-demo-app:latest 103 | name: webserver 104 | resources: 105 | requests: 106 | cpu: "100m" 107 | memory: "128Mi" 108 | volumeMounts: 109 | - mountPath: /run 110 | name: run 111 | - mountPath: /var/cache 112 | name: cache 113 | env: 114 | - name: POD_NAME 115 | valueFrom: 116 | fieldRef: 117 | fieldPath: metadata.name 118 | - name: POD_NAMESPACE 119 | valueFrom: 120 | fieldRef: 121 | fieldPath: metadata.namespace 122 | - name: APP_NAME 123 | valueFrom: 124 | fieldRef: 125 | fieldPath: metadata.labels['app'] 126 | ports: 127 | - containerPort: 8080 128 | protocol: TCP 129 | - containerPort: 9080 # PROXY protocol 130 | protocol: TCP 131 | readinessProbe: 132 | httpGet: 133 | path: / 134 | port: 8080 135 | livenessProbe: 136 | httpGet: 137 | path: / 138 | port: 8080 139 | securityContext: 140 | readOnlyRootFilesystem: true 141 | allowPrivilegeEscalation: false 142 | runAsNonRoot: true 143 | runAsUser: 101 144 | -------------------------------------------------------------------------------- /ingresses.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | labels: 6 | app: aws-alb-demo-frontend 7 | name: aws-alb-demo-frontend 8 | spec: 9 | type: NodePort 10 | ports: 11 | - name: http 12 | port: 80 13 | protocol: TCP 14 | targetPort: 8080 15 | selector: 16 | app: aws-lb-demo-frontend 17 | --- 18 | apiVersion: v1 19 | kind: Service 20 | metadata: 21 | labels: 22 | app: aws-alb-demo-backend 23 | name: aws-alb-demo-backend 24 | spec: 25 | type: NodePort 26 | ports: 27 | - name: http 28 | port: 80 29 | protocol: TCP 30 | targetPort: 8080 31 | selector: 32 | app: aws-lb-demo-backend 33 | --- 34 | apiVersion: networking.k8s.io/v1beta1 35 | kind: Ingress 36 | metadata: 37 | name: aws-alb-ip-demo-frontend 38 | annotations: 39 | external-dns.alpha.kubernetes.io/hostname: "aws-alb-ip.demo.otterley.org" 40 | kubernetes.io/ingress.class: alb 41 | alb.ingress.kubernetes.io/target-type: ip 42 | alb.ingress.kubernetes.io/scheme: internet-facing 43 | alb.ingress.kubernetes.io/group.name: ip 44 | spec: 45 | backend: 46 | serviceName: aws-alb-demo-frontend 47 | servicePort: 80 48 | --- 49 | apiVersion: networking.k8s.io/v1beta1 50 | kind: Ingress 51 | metadata: 52 | name: aws-alb-ip-demo-backend 53 | annotations: 54 | kubernetes.io/ingress.class: alb 55 | alb.ingress.kubernetes.io/target-type: ip 56 | alb.ingress.kubernetes.io/scheme: internet-facing 57 | alb.ingress.kubernetes.io/group.name: ip 58 | spec: 59 | rules: 60 | - http: 61 | paths: 62 | - path: /backend/* 63 | backend: 64 | serviceName: aws-alb-demo-backend 65 | servicePort: 80 66 | #--- 67 | #apiVersion: networking.k8s.io/v1beta1 68 | #kind: Ingress 69 | #metadata: 70 | # name: aws-alb-instance-demo-frontend 71 | # annotations: 72 | # external-dns.alpha.kubernetes.io/hostname: "aws-alb-instance.demo.otterley.org" 73 | # kubernetes.io/ingress.class: alb 74 | # alb.ingress.kubernetes.io/target-type: instance 75 | # alb.ingress.kubernetes.io/scheme: internet-facing 76 | # alb.ingress.kubernetes.io/group.name: instance 77 | #spec: 78 | # backend: 79 | # serviceName: aws-alb-demo-frontend 80 | # servicePort: 80 81 | #--- 82 | #apiVersion: networking.k8s.io/v1beta1 83 | #kind: Ingress 84 | #metadata: 85 | # name: aws-alb-instance-demo-backend 86 | # annotations: 87 | # kubernetes.io/ingress.class: alb 88 | # alb.ingress.kubernetes.io/target-type: instance 89 | # alb.ingress.kubernetes.io/scheme: internet-facing 90 | # alb.ingress.kubernetes.io/group.name: instance 91 | #spec: 92 | # rules: 93 | # - http: 94 | # paths: 95 | # - path: /backend/* 96 | # backend: 97 | # serviceName: aws-alb-demo-backend 98 | # servicePort: 80 99 | -------------------------------------------------------------------------------- /nlb-services.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: aws-nlb-ip-demo 6 | name: aws-nlb-ip-demo 7 | annotations: 8 | external-dns.alpha.kubernetes.io/hostname: "aws-nlb-ip.demo.otterley.org" 9 | service.beta.kubernetes.io/aws-load-balancer-type: "nlb-ip" 10 | spec: 11 | type: LoadBalancer # Use NodePort on EKS <= 1.17 12 | ports: 13 | - name: http 14 | port: 80 15 | protocol: TCP 16 | targetPort: 8080 17 | selector: 18 | app: aws-lb-demo-frontend 19 | --- 20 | apiVersion: v1 21 | kind: Service 22 | metadata: 23 | labels: 24 | app: aws-nlb-ip-proxyprotocol-demo 25 | name: aws-nlb-ip-proxyprotocol-demo 26 | annotations: 27 | external-dns.alpha.kubernetes.io/hostname: "aws-nlb-ip-proxyproto.demo.otterley.org" 28 | service.beta.kubernetes.io/aws-load-balancer-type: "nlb-ip" 29 | service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*" 30 | spec: 31 | type: LoadBalancer # Use NodePort on EKS <= 1.17 32 | ports: 33 | - name: http 34 | port: 80 35 | protocol: TCP 36 | targetPort: 9080 37 | selector: 38 | app: aws-lb-demo-frontend 39 | #--- 40 | #apiVersion: v1 41 | #kind: Service 42 | #metadata: 43 | # labels: 44 | # app: aws-nlb-instance-demo 45 | # name: aws-nlb-instance-demo 46 | # annotations: 47 | # # In-tree load balancer that uses Instance-type targets 48 | # external-dns.alpha.kubernetes.io/hostname: "aws-nlb-instance.demo.otterley.org" 49 | # service.beta.kubernetes.io/aws-load-balancer-type: "nlb" 50 | #spec: 51 | # type: LoadBalancer 52 | # ports: 53 | # - name: http 54 | # port: 80 55 | # protocol: TCP 56 | # targetPort: 8080 57 | # selector: 58 | # app: aws-lb-demo-frontend 59 | -------------------------------------------------------------------------------- /policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": "ec2:DescribeNetworkInterfaces", 7 | "Resource": "*" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /security-group-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: vpcresources.k8s.aws/v1beta1 2 | kind: SecurityGroupPolicy 3 | metadata: 4 | name: aws-lb-demo-frontend 5 | namespace: default 6 | spec: 7 | podSelector: 8 | matchLabels: 9 | app: aws-lb-demo-frontend 10 | securityGroups: 11 | groupIds: 12 | - sg-0a064359cdea6c0a1 13 | --- 14 | apiVersion: vpcresources.k8s.aws/v1beta1 15 | kind: SecurityGroupPolicy 16 | metadata: 17 | name: aws-lb-demo-backend 18 | namespace: default 19 | spec: 20 | podSelector: 21 | matchLabels: 22 | app: aws-lb-demo-backend 23 | securityGroups: 24 | groupIds: 25 | - sg-08ef3010024dc0259 26 | --------------------------------------------------------------------------------