diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4d16d8c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +.git +.gitignore +.editorconfig + +# Compiled files +**/.terraform/* +**/.terragrunt-cache/* +*.tfstate +*.tfstate.* + +# Module directory +.terraform +**/.idea +**/*.iml + +**/.build-harness +**/build-harness diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..bed3c96 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,14 @@ +# Use this file to define individuals or teams that are responsible for code in a repository. +# Read more: +# +# Order is important: the last matching pattern takes the most precedence + +# These owners will be the default owners for everything +* @cloudposse/engineering @cloudposse/contributors + +# Cloud Posse must review any changes to Makefiles +**/Makefile @cloudposse/engineering +**/Makefile.* @cloudposse/engineering + +# Cloud Posse must review any changes to GitHub actions +.github/* @cloudposse/engineering diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..f3df96b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,37 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: 'bug' +assignees: '' + +--- + +Found a bug? Maybe our [Slack Community](https://slack.cloudposse.com) can help. + +[![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + +## Describe the Bug +A clear and concise description of what the bug is. + +## Expected Behavior +A clear and concise description of what you expected to happen. + +## Steps to Reproduce +Steps to reproduce the behavior: +1. Go to '...' +2. Run '....' +3. Enter '....' +4. See error + +## Screenshots +If applicable, add screenshots or logs to help explain your problem. + +## Environment (please complete the following information): + +Anything that will help us triage the bug will help. Here are some ideas: + - OS: [e.g. Linux, OSX, WSL, etc] + - Version [e.g. 10.15] + +## Additional Context +Add any other context about the problem here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..76ae6d6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,18 @@ +blank_issues_enabled: false + +contact_links: + + - name: Community Slack Team + url: https://cloudposse.com/slack/ + about: |- + Please ask and answer questions here. + + - name: Office Hours + url: https://cloudposse.com/office-hours/ + about: |- + Join us every Wednesday for FREE Office Hours (lunch & learn). + + - name: DevOps Accelerator Program + url: https://cloudposse.com/accelerate/ + about: |- + Own your infrastructure in record time. We build it. You drive it. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..39a8686 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,36 @@ +--- +name: Feature Request +about: Suggest an idea for this project +title: '' +labels: 'feature request' +assignees: '' + +--- + +Have a question? Please checkout our [Slack Community](https://slack.cloudposse.com) or visit our [Slack Archive](https://archive.sweetops.com/). + +[![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) + +## Describe the Feature + +A clear and concise description of what the bug is. + +## Expected Behavior + +A clear and concise description of what you expected to happen. + +## Use Case + +Is your feature request related to a problem/challenge you are trying to solve? Please provide some additional context of why this feature or capability will be valuable. + +## Describe Ideal Solution + +A clear and concise description of what you want to happen. If you don't know, that's okay. + +## Alternatives Considered + +Explain what alternative solutions or features you've considered. + +## Additional Context + +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..e69de29 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..4b8f32d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +## what +* Describe high-level what changed as a result of these commits (i.e. in plain-english, what do these changes mean?) +* Use bullet points to be concise and to the point. + +## why +* Provide the justifications for the changes (e.g. business case). +* Describe why these changes were made (e.g. why do these commits fix the problem?) +* Use bullet points to be concise and to the point. + +## references +* Link to any supporting github issues or helpful documentation to add some context (e.g. stackoverflow). +* Use `closes #123`, if this PR closes a GitHub issue `#123` + diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml new file mode 100644 index 0000000..ed9361f --- /dev/null +++ b/.github/workflows/build-and-push.yml @@ -0,0 +1,23 @@ +name: docker +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened] + +jobs: + update: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v1 + - name: docker/build-and-push + uses: docker/build-push-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + repository: ${{ github.repository }} + registry: registry-1.docker.io + tag_with_ref: true + tag_with_sha: true diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..aeb83d5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,49 @@ +FROM cloudposse/geodesic:0.132.1 + +# Geodesic message of the Day +ENV MOTD_URL="https://geodesic.sh/motd" + +# Some configuration options for Geodesic +ENV AWS_SAML2AWS_ENABLED=true +ENV AWS_VAULT_ENABLED=false +ENV GEODESIC_TERRAFORM_WORKSPACE_PROMPT_ENABLED=true +ENV DIRENV_ENABLED=false + +ENV DOCKER_IMAGE="cloudposse/reference-architectures" +ENV DOCKER_TAG="latest" +ENV NAMESPACE="eg" + +# Geodesic banner message +ENV BANNER="sweet ops" + +# Pin kubectl to version 1.15 +RUN apk add kubectl-1.15@cloudposse + +# Install terraform +RUN apk add terraform@cloudposse + +# Install helmfile +RUN apk add helmfile@cloudposse + +# Install saml2aws +# https://github.com/Versent/saml2aws#linux +RUN apk add saml2aws@cloudposse + +# Install assume-role +RUN apk add assume-role@cloudposse + +# Install variant2 overwriting variant +RUN apk add variant2@cloudposse + +# Install the "docker" command to interact with the host's Docker daemon +RUN apk add -u docker-cli + +# Limit Makefile searches set up by Geodesic +# Allow a single Makefile to serve all child directories +ENV MAKE_INCLUDES="Makefile.settings ../Makefile.parent Makefile" + +COPY rootfs/ / + +COPY projects/ /projects/ + +WORKDIR /projects/ diff --git a/Makefile b/Makefile index ee22cf7..786b0cb 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,38 @@ -# Import the cloudposse/build-harness -include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) --include tasks/Makefile.* +export DOCKER_ORG ?= cloudposse +export DOCKER_IMAGE ?= $(DOCKER_ORG)/reference-architectures +export DOCKER_TAG ?= latest +export DOCKER_IMAGE_NAME ?= $(DOCKER_IMAGE):$(DOCKER_TAG) +export APP_NAME ?= geodesic.sh +GEODESIC_INSTALL_PATH ?= /usr/local/bin +export INSTALL_PATH ?= $(GEODESIC_INSTALL_PATH) +export SCRIPT = $(INSTALL_PATH)/$(APP_NAME) # The target called when calling `make` with no arguments export DEFAULT_HELP_TARGET = help/short +# Import the cloudposse/build-harness +-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness) + +## Initialize build-harness, install deps, build docker container, install wrapper script and run shell +all: init deps build install run + @exit 0 + +## Install dependencies (if any) +deps: + @exit 0 + +## Build docker image +build: + @make --no-print-directory docker/build + +## Push docker image to registry +push: + docker push $(DOCKER_IMAGE) + +## Install wrapper script from geodesic container +install: + @docker run --rm $(DOCKER_IMAGE_NAME) | bash -s $(DOCKER_TAG) || (echo "Try: sudo make install"; exit 1) + +## Start the geodesic shell by calling wrapper script +run: + $(SCRIPT) diff --git a/README.md b/README.md index f051c98..a92642b 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,12 @@ It's 100% Open Source and licensed under the [APACHE2](LICENSE). +## Screenshots + + +![demo](docs/screenshot.png) +*Example of using the `geodesic` shell as a build a docker image built from the `cloudposse/reference-architectures`* + ## Introduction diff --git a/README.yaml b/README.yaml index 4af7cc5..669adf2 100644 --- a/README.yaml +++ b/README.yaml @@ -92,6 +92,12 @@ introduction: |- The master account owns the top-level DNS zone and then delegates NS authority to each member account. +# Screenshots +screenshots: + - name: "demo" + description: "Example of using the `geodesic` shell as a build a docker image built from the `cloudposse/reference-architectures`" + url: "docs/screenshot.png" + quickstart: |- ### Assumptions diff --git a/docs/screenshot.png b/docs/screenshot.png new file mode 100644 index 0000000..e412ca0 Binary files /dev/null and b/docs/screenshot.png differ diff --git a/projects/Makefile.parent b/projects/Makefile.parent new file mode 100644 index 0000000..45c0036 --- /dev/null +++ b/projects/Makefile.parent @@ -0,0 +1,70 @@ +init: .terraform/terraform.tfstate + +workspace/% %.workspace: conf/%.tfvars .terraform/terraform.tfstate + @terraform workspace select $* || terraform workspace new $* + +plan: + @if [[ -n $${WORKSPACE:=$$(cat .terraform/environment 2>/dev/null)} ]]; then \ + echo terraform plan -var-file conf/$${WORKSPACE}.tfvars -out $${WORKSPACE}.planfile; \ + terraform plan -var-file conf/$${WORKSPACE}.tfvars -out $${WORKSPACE}.planfile; \ + else \ + echo You must first select a workspace with "'make workspace/...'" >&2; exit 4; \ + fi + +apply: + @if [[ -n $${WORKSPACE:=$$(cat .terraform/environment 2>/dev/null)} ]]; then \ + if [[ -s $${WORKSPACE}.planfile ]]; then \ + echo terraform apply $${WORKSPACE}.planfile; \ + terraform apply $${WORKSPACE}.planfile && rm $${WORKSPACE}.planfile; \ + else \ + echo "You must first 'make plan'" >&2; exit 3; \ + fi; \ + else \ + echo You must first select a workspace with "'make workspace/...'" >&2; exit 4; \ + fi + +clean: + rm -rf .terraform *.planfile + +# refresh the terraform state & outputs +refresh: + @if [[ -n $${WORKSPACE:=$$(cat .terraform/environment 2>/dev/null)} ]]; then \ + echo terraform refresh -var-file conf/$${WORKSPACE}.tfvars; \ + terraform refresh -var-file conf/$${WORKSPACE}.tfvars; \ + else \ + echo You must first select a workspace with "'make workspace/...'" >&2; exit 4; \ + fi + +.terraform/terraform.tfstate: + terraform init + +## make .plan will always run "terraform plan" to create a planfile for workspace "" +## make .planfile will run "terraform plan" to create a planfile for workspace "" if it is +## out of date with respect to source files +%.plan %.planfile: conf/%.tfvars *.tf workspace/% + terraform plan -var-file conf/$*.tfvars -out $*.planfile + +## make .apply will run "terraform apply" using an existing ".planfile" file for workspace "" +%.apply: workspace/% + @if [[ -s $*.planfile ]]; then \ + echo terraform apply $*.planfile; \ + terraform apply $*.planfile && rm $*.planfile; \ + else \ + echo "You must first 'make $*.planfile'" >&2; exit 3; \ + fi; \ + +## make .sync will run "terraform plan" then "terraform apply" for workspace "" +%.sync: conf/%.tfvars workspace/% %.planfile + terraform apply $*.planfile && rm $*.planfile + +# refresh the terraform state & outputs +%.refresh: workspace/% + terraform refresh -var-file conf/$*.tfvars + +# output the terraform state outputs +%.output: workspace/% + @ terraform output + +.PHONY: init plan apply clean sync refresh output + +.SECONDARY: diff --git a/projects/README.md b/projects/README.md new file mode 100644 index 0000000..1ace8ad --- /dev/null +++ b/projects/README.md @@ -0,0 +1,62 @@ +# Infrastructure Projects + +Terraform and Kubernetes projects exist in here. + +## Terraform workflow + +Terraform operates on a "workspace". We have a named workspace for each AWS account. +In these examples, we will use "dev" as the workspace we are operating on, but "dev" +can be replaced with any workspace name for which there is a `conf/$workspace.tfvars` file. + +### Manual, multi-step workflow + +Remember, replace "dev" with whatever valid workspace name you want. + +```bash +make init # initializes Terraform +make workspace/dev # selects workspace "dev" +make plan # make planfile for current workspace +make apply # apply planfile for current workspace, delete planfile on success +``` + +### Automatic, single-step workflow + +Remember, replace "dev" with whatever valid workspace name you want. + +- Generate Terraform planfile (the output of `terraform plan` and input to `terraform apply`), if needed: + + ```bash + make dev.planfile + ``` + +- Optionally/alternatively: (re-)generate Terraform planfile regardless of whether there is a current up-to-date one already: + + ```bash + make dev.plan + ``` + +- Apply an existing planfile and delete it on success. Will fail if planfile does not exist: + + ```bash + make dev.apply + ``` + +## Cold Start + +Initiating the project requires a specific order. + +* Initialize the [tfstate-backend](tfstate-backend/README.md) +* Create the [accounts](account/README.md) +* Configure [SSO](sso/README.md) with a GSuite Admin +* Configure [primary IAM roles](iam-primary-roles/README.md) +* Configure [delegated IAM roles](iam-delegated-roles/) +* Configure [VPCs](vpc/) +* Configure [CloudTrail bucket](cloudtrail-bucket/) on `master` +* Configure [CloudTrail](cloudtrail/) per account +* Configure [primary DNS zones](dns-primary/) +* Configure [delegated DNS zones](dns-delegated/) +* Configure [EKS clusters](eks/) +* Configure [EFS](efs/) +* Configure [EKS IAM Roles](eks-iam/) +* Configure [Helm external-dns](helmfiles/external-dns) +* Configure [Helm metrics-server](helmfiles/kube-state-metrics) diff --git a/rootfs/.gitignore b/rootfs/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/rootfs/etc/profile.d/aws-saml2aws.sh b/rootfs/etc/profile.d/aws-saml2aws.sh new file mode 100644 index 0000000..d25ab71 --- /dev/null +++ b/rootfs/etc/profile.d/aws-saml2aws.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +if [[ $GEODESIC_TRACE =~ saml ]]; then + export _GEODESIC_TRACE_SAML=true +else + unset _GEODESIC_TRACE_SAML +fi + +if [ "${AWS_SAML2AWS_ENABLED}" == "true" ]; then + [[ -n $_GEODESIC_TRACE_SAML ]] && echo "trace: Executing aws-saml2aws.sh" + if command -v saml2aws >/dev/null; then + [[ -n $_GEODESIC_TRACE_SAML ]] && green "trace: saml2aws installed" + else + [[ -n $_GEODESIC_TRACE_SAML ]] && red "trace: saml2aws not installed" + exit 1 + fi + + ln -sf /localhost/.saml2aws ${HOME} +fi