From 98cfbd61d4ff65b2c76fc1bca29a4c6d183c0edc Mon Sep 17 00:00:00 2001 From: Joakim Olsson Date: Thu, 20 Jun 2019 13:07:42 +0200 Subject: [PATCH] Initial commit --- .editorconfig | 0 .gitignore | 1 + .gitlab-ci.yml | 27 ++++++++++++ Dockerfile | 51 ++++++++++++++++++++++ README.MD | 27 ++++++++++++ deployment_files/deploy.yaml | 85 ++++++++++++++++++++++++++++++++++++ nginx.conf | 62 ++++++++++++++++++++++++++ start.sh | 18 ++++++++ 8 files changed, 271 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 Dockerfile create mode 100644 README.MD create mode 100644 deployment_files/deploy.yaml create mode 100644 nginx.conf create mode 100755 start.sh diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bff2d76 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.iml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..4547a70 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,27 @@ +stages: + - build + - deploy-prod + +variables: + DOCKER_HOST: tcp://docker:2375/ + +image: registry.gitlab.com/sparetimecoders/build-tools:master + +build: + stage: build + services: + - docker:dind + script: + - build + - push + +deploy-to-prod: + stage: deploy-prod + when: on_success + script: + - echo Deploy to prod. + - deploy prod + environment: + name: prod + only: + - master diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..acc31f2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +FROM ubuntu + +# Install prerequisites for Nginx compile +RUN apt-get update && \ + apt-get install -y wget tar gcc libpcre3-dev zlib1g-dev make libssl-dev libluajit-5.1-dev curl jq + +# Download Nginx +WORKDIR /tmp +RUN wget http://nginx.org/download/nginx-1.16.0.tar.gz -O nginx.tar.gz && \ + mkdir nginx && \ + tar xf nginx.tar.gz -C nginx --strip-components=1 + +# Download Nginx modules +RUN wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz -O ngx_devel_kit.tar.gz && \ + mkdir ngx_devel_kit && \ + tar xf ngx_devel_kit.tar.gz -C ngx_devel_kit --strip-components=1 +RUN wget https://github.com/openresty/set-misc-nginx-module/archive/v0.32.tar.gz -O set-misc-nginx-module.tar.gz && \ + mkdir set-misc-nginx-module && \ + tar xf set-misc-nginx-module.tar.gz -C set-misc-nginx-module --strip-components=1 +RUN wget https://github.com/openresty/lua-nginx-module/archive/v0.10.15.tar.gz -O lua-nginx-module.tar.gz && \ + mkdir lua-nginx-module && \ + tar xf lua-nginx-module.tar.gz -C lua-nginx-module --strip-components=1 + +# Build Nginx +WORKDIR nginx +RUN ./configure --sbin-path=/usr/local/sbin \ + --conf-path=/etc/nginx/nginx.conf \ + --pid-path=/var/run/nginx.pid \ + --error-log-path=/var/log/nginx/error.log \ + --http-log-path=/var/log/nginx/access.log \ + --with-http_ssl_module \ + --add-module=/tmp/ngx_devel_kit \ + --add-module=/tmp/set-misc-nginx-module \ + --add-module=/tmp/lua-nginx-module && \ + make && \ + make install + + +# Expose ports +EXPOSE 80 + +# forward request and error logs to docker log collector +RUN ln -sf /dev/stdout /var/log/nginx/access.log \ + && ln -sf /dev/stderr /var/log/nginx/error.log + +# Apply Nginx config +ADD nginx.conf /etc/nginx/nginx.conf +ADD start.sh /start.sh + +# Set default command +ENTRYPOINT ["/start.sh"] diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..e3fdd61 --- /dev/null +++ b/README.MD @@ -0,0 +1,27 @@ +# nginx-s3-upload + +Uploads files to s3 bucket. Basically an [nginx](http://nginx.org/en/docs/) which `proxy_pass` `HTTP POST` requests to [S3](https://aws.amazon.com/s3) directly + +## Configuration +Environment variables are used to provide configuration. + + | Variable name | Comment | + |----------------|---------| + | S3_BUCKET_NAME | Mandatory | + | AWS_ACCESS_KEY_ID | Optional - will be fetched from IAM policy on AWS | + | AWS_SECRET_ACCESS_KEY | Optional - will be fetched from IAM policy on AWS | + + +## Testing + docker run --rm --env AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} --env AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} --env S3_BUCKET_NAME=upload.paidit.se -p 8000:80 875131241629.dkr.ecr.eu-west-1.amazonaws.com/nginx-s3-upload + +Try it out: + + curl localhost:8000/upload -d 'some data' -v + ... + > PUT /uploads HTTP/1.1 + ... + < X-File-URL: https://uploads.paidit.se/59389abb021973a41d05e0d7d79949b17b83b142058a3704c98f274b6e563cfc403e64db6550f233 + ... + +The header `X-File-URL` will contain the URL to the uploaded file. diff --git a/deployment_files/deploy.yaml b/deployment_files/deploy.yaml new file mode 100644 index 0000000..c0ca4da --- /dev/null +++ b/deployment_files/deploy.yaml @@ -0,0 +1,85 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx-s3-upload + name: nginx-s3-upload-deployment + annotations: + kubernetes.io/change-cause: "${TIMESTAMP} Deployed commit id: ${COMMIT}" +spec: + replicas: 2 + selector: + matchLabels: + app: nginx-s3-upload + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + template: + metadata: + labels: + app: nginx-s3-upload + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: "app" + operator: In + values: + - nginx-s3-upload + topologyKey: kubernetes.io/hostname + containers: + - name: nginx-s3-upload + readinessProbe: + httpGet: + path: /healthcheck + port: 80 + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 + imagePullPolicy: IfNotPresent + image: registry.gitlab.com/paidit-se/nginx-s3-upload:${COMMIT} + env: + - name: S3_BUCKET_NAME + value: upload.paidit.se + ports: + - containerPort: 80 + +--- + +apiVersion: v1 +kind: Service +metadata: + name: nginx-s3-upload +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + app: nginx-s3-upload + type: ClusterIP + +--- + +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: nginx-s3-upload + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/proxy-body-size: 1g +spec: + rules: + - host: 'upload.paidit.se' + http: + paths: + - backend: + serviceName: nginx-s3-upload + servicePort: 80 + path: / diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..beeb6e5 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,62 @@ +env AWS_ACCESS_KEY_ID; +env AWS_SECRET_ACCESS_KEY; +env S3_BUCKET_NAME; + +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + server { + listen 80; + client_max_body_size 0; + + location /healthcheck { + add_header Content-Type text/plain; + return 200 'Ok'; + access_log off; + } + + location ~* ^/uploads { + if ($request_method = 'OPTIONS') { + # Tell client that this pre-flight info is valid for 20 days + add_header 'Access-Control-Allow-Origin' "*" ; + add_header 'Access-Control-Allow-Credentials' 'true' ; + add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS' ; + add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With'; + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + if ($request_method != PUT) { + return 404; + } + + set_secure_random_alphanum $prefix 64; + set_sha1 $prefixsha $prefix; + set_by_lua $date "return ngx.cookie_time(ngx.time())"; + set_by_lua $day "return ngx.today()"; + set_sha1 $datesha $date; + set $key $prefixsha$datesha; + set_by_lua $bucket "return os.getenv('S3_BUCKET_NAME')"; + set $url https://$bucket.s3.amazonaws.com/$day/$key; + set $returnurl https://uploads.paidit.se/$day/$key; + set $acl public-read; + + proxy_set_header x-amz-acl $acl; + proxy_set_header x-amz-date $date; + proxy_hide_header x-amz-id-2; + proxy_hide_header x-amz-request-id; + add_header X-File-URL $returnurl; + + resolver 8.8.8.8 valid=300s; + resolver_timeout 10s; + add_header 'Access-Control-Expose-Headers' 'X-File-Url'; + + proxy_pass $url; + } + } +} diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..6c6011c --- /dev/null +++ b/start.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set +u + +if [[ -z ${AWS_SECRET_ACCESS_KEY} ]] +then + IAM_ROLE=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/) + JSON=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/${IAM_ROLE}) + export AWS_ACCESS_KEY_ID=$(echo ${JSON} | jq -r '.AccessKeyId') + export AWS_SECRET_ACCESS_KEY=$(echo ${JSON} | jq -r '.SecretAccessKey') +fi + +set -euo pipefail +: ${S3_BUCKET_NAME:?"S3_BUCKET_NAME must be set"} +: ${AWS_ACCESS_KEY_ID:?"AWS_ACCESS_KEY_ID must be set or be possible to fetch from meta-data service on AWS"} +: ${AWS_SECRET_ACCESS_KEY:?"AWS_ACCESS_KEY_ID must be set or be possible to fetch from meta-data service on AWS"} + +exec nginx -g 'daemon off;'