From 80e5833aa57d57da026895601f46de36f5617e85 Mon Sep 17 00:00:00 2001 From: Plamen Nedkov Date: Sun, 28 Jan 2024 23:55:52 -0600 Subject: [PATCH] Add instructions for running on AWS EKS --- README.md | 13 +++ k8s/README.md | 156 +++++++++++++++++++++++++++ k8s/alb-ingress-curl-workaround.yaml | 63 +++++++++++ k8s/alb-ingress.yaml | 24 +++++ k8s/eks-cluster.yaml | 34 ++++++ k8s/ipask.yaml | 49 +++++++++ 6 files changed, 339 insertions(+) create mode 100644 k8s/README.md create mode 100644 k8s/alb-ingress-curl-workaround.yaml create mode 100644 k8s/alb-ingress.yaml create mode 100644 k8s/eks-cluster.yaml create mode 100644 k8s/ipask.yaml diff --git a/README.md b/README.md index 66b14a0..3cb72ad 100644 --- a/README.md +++ b/README.md @@ -215,3 +215,16 @@ cd ipask/ ``` + +--- + +
+ + +## Run on AWS Elastic Kubernetes Service + + + +[k8s/README.md](k8s/README.md) + +
diff --git a/k8s/README.md b/k8s/README.md new file mode 100644 index 0000000..22c48aa --- /dev/null +++ b/k8s/README.md @@ -0,0 +1,156 @@ +# Deploy IP Ask on AWS EKS + +Non-comprehensive guide for running IP Ask (or any similar application) in [AWS EKS](https://aws.amazon.com/eks/). + +--- + +## Prerequisites + +- AWS account + +- AWS user with an access key and [sufficient rights](https://eksctl.io/usage/minimum-iam-policies/) + +- Domain with a DNS zone managed by [AWS Route 53](https://aws.amazon.com/route53/) + +- Some free time + +--- + +## Software installation and configuration + +- Install and configure [awscli](https://aws.amazon.com/cli/) + + ```sh + $ pacman -S aws-cli-v2 + ... + $ aws configure + AWS Access Key ID [None]: + AWS Secret Access Key [None]: + Default region name [None]: us-east-1 + Default output format [None]: json + $ + ``` + +- Install [eksctl](https://eksctl.io/) + + ```sh + pacman -S eksctl + ``` + +- Install [kubectl](https://kubernetes.io/docs/reference/kubectl/) + + ```sh + pacman -S kubectl + ``` + +- Request a public SSL/TLS certificate from [AWS ACM](https://aws.amazon.com/certificate-manager/) and validate it with a DNS record + + ```sh + aws acm request-certificate \ + --domain-name ipask.me \ + --subject-alternative-names "ipask.me" "*.ipask.me" \ + --key-algorithm EC_secp384r1 \ + --validation-method DNS \ + --idempotency-token 1000 \ + --options CertificateTransparencyLoggingPreference=ENABLED + ``` + + Note that `CertificateTransparencyLoggingPreference` must be `enabled`. + +- Set and export environment variables that are required for some of the commands later on + + ```sh + export AWS_EKS_CLUSTER_NAME=my_eks_cluster + export AWS_EKS_REGION=$(aws configure get region) + export AWS_EKS_VERSION=1.28 + export AWS_EKS_CIDR="10.250.0.0/16" + export AWS_IAM_CERT_ARN="SSL/TLS certificate's ARN" + export IPASK_VERSION="The latest tag for the prestigen/ipask image" + ``` + +--- + +## Create the AWS EKS cluster + +- Create + + All `AWS_EKS_*` environment variables must be set. + + ```sh + envsubst < eks-cluster.yaml | eksctl create cluster -f - + ``` + +- Test + + ```sh + $ kubectl get nodes + NAME STATUS ROLES AGE VERSION + ip-192-168-10-86.ec2.internal Ready 1m v1.28.3-eks-e71965b + ip-192-168-44-82.ec2.internal Ready 1m v1.28.3-eks-e71965b + $ + ``` + +--- + +## Install AWS LB Controller for the Kubernetes cluster + +Follow the [official guide](https://docs.aws.amazon.com/eks/latest/userguide/aws-load-balancer-controller.html) + +--- + +## Build and push the container to hub.docker.com + +Handled by the CI/CD + +--- + +## Deploy the web application to AWS EKS + +The `IPASK_VERSION` environment variable must be set. + +```sh +envsubst < k8s/ipask.yaml | kubectl apply -f - +``` + +--- + +## Create the K8s Ingress resource(s) and the AWS Application Load Balancer + +The `AWS_IAM_CERT_ARN` environment variable must be set. + +Choose option `A` **_or_** `B`. + +- (Option A): All HTTP requests are automatically redirected to HTTPS + + ```sh + envsubst < alb-ingress.yaml | kubectl apply -f - + ``` + + Note: Due to the fact that `curl` does not automatically follow the new location when the server returns 301, it must be supplied with either the protocol (`https://`) or the `-L` flag: + + ```sh + curl -L ipask.me + curl https://ipask.me + ``` + +- (Option B): All HTTP requests except the ones coming from `curl` are redirected to HTTPS + + ```sh + envsubst < alb-ingress-curl-workaround.yaml | kubectl apply -f - + ``` + + With this solution, the HTTP-to-HTTPS redirection is disabled for `curl`, which is why the following command will work but the communication will be unencrypted: + + ```sh + curl ipask.me + ``` + + `wget` on the other hand automatically initiates a new connection to the new HTTPS location provided in the `301` response: + + ```sh + wget -qO - ipask.me + ``` + +--- + +## Create DNS "A" record that points to the Application Load Balancer diff --git a/k8s/alb-ingress-curl-workaround.yaml b/k8s/alb-ingress-curl-workaround.yaml new file mode 100644 index 0000000..2b8790a --- /dev/null +++ b/k8s/alb-ingress-curl-workaround.yaml @@ -0,0 +1,63 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ipask-ingress + annotations: + alb.ingress.kubernetes.io/group.name: ipask-ingress-group + alb.ingress.kubernetes.io/group.order: "0" + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]' + alb.ingress.kubernetes.io/backend-protocol: "HTTP" + alb.ingress.kubernetes.io/actions.bypass-ssl: > + {"type":"forward", "forwardConfig":{"targetGroups":[{"serviceName":"ipask-svc", "servicePort":"8080", "weight":1}]}} + alb.ingress.kubernetes.io/conditions.bypass-ssl: > + [{"field":"http-header", "httpHeaderConfig":{"httpHeaderName":"User-Agent", "values":["curl/*"]}}] + alb.ingress.kubernetes.io/actions.redirect-to-https: > + {"Type":"redirect","RedirectConfig":{"protocol":"HTTPS","port":"443","statusCode":"HTTP_301"}} +spec: + ingressClassName: "alb" + rules: + - host: ipask.me + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: bypass-ssl + port: + name: use-annotation + - path: / + pathType: Prefix + backend: + service: + name: redirect-to-https + port: + name: use-annotation +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ipask-ingress-secure + annotations: + alb.ingress.kubernetes.io/group.name: ipask-ingress-group + alb.ingress.kubernetes.io/group.order: "1" + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]' + alb.ingress.kubernetes.io/backend-protocol: "HTTP" + alb.ingress.kubernetes.io/certificate-arn: ${AWS_IAM_CERT_ARN} +spec: + ingressClassName: "alb" + rules: + - host: ipask.me + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: ipask-svc + port: + number: 8080 diff --git a/k8s/alb-ingress.yaml b/k8s/alb-ingress.yaml new file mode 100644 index 0000000..ca8b7ba --- /dev/null +++ b/k8s/alb-ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: ipask-ingress + annotations: + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]' + alb.ingress.kubernetes.io/backend-protocol: "HTTP" + alb.ingress.kubernetes.io/ssl-redirect: "443" + alb.ingress.kubernetes.io/certificate-arn: ${AWS_IAM_CERT_ARN} +spec: + ingressClassName: "alb" + rules: + - host: ipask.me + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: ipask-svc + port: + number: 8080 diff --git a/k8s/eks-cluster.yaml b/k8s/eks-cluster.yaml new file mode 100644 index 0000000..fb6c79c --- /dev/null +++ b/k8s/eks-cluster.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: eksctl.io/v1alpha5 +kind: ClusterConfig + +metadata: + name: ${AWS_EKS_CLUSTER_NAME} + region: ${AWS_EKS_REGION} + version: "${AWS_EKS_VERSION}" + +kubernetesNetworkConfig: + IpFamily: ipv4 + serviceIPv4CIDR: ${AWS_EKS_CIDR} + +iam: + withOIDC: true + +managedNodeGroups: + - name: ng1 + instanceType: t3.small + desiredCapacity: 2 + minSize: 2 + maxSize: 2 + volumeSize: 10 + volumeType: "gp3" + volumeEncrypted: true + volumeIOPS: 3000 + volumeThroughput: 125 + labels: { role: workers } + tags: + nodegroup-role: worker + #privateNetworking: true +# ssh: +# allow: true +# publicKeyName: myPublicKeyName diff --git a/k8s/ipask.yaml b/k8s/ipask.yaml new file mode 100644 index 0000000..77b3181 --- /dev/null +++ b/k8s/ipask.yaml @@ -0,0 +1,49 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ipask + #labels: + # app: ipask +spec: + replicas: 2 + selector: + matchLabels: + app: ipask + revisionHistoryLimit: 5 + progressDeadlineSeconds: 300 + minReadySeconds: 10 + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + template: + metadata: + labels: + app: ipask + spec: + containers: + - name: ipask-ctr + image: prestigen/ipask:${IPASK_VERSION} + ports: + - containerPort: 8080 + imagePullPolicy: Always + env: + - name: IPASK_PROD + value: "true" + - name: GEOIP + value: "true" + - name: REVERSE_DNS_LOOKUP + value: "true" +--- +apiVersion: v1 +kind: Service +metadata: + name: ipask-svc +spec: + type: ClusterIP + ports: + - port: 8080 + targetPort: 8080 + selector: + app: ipask