{"id":21202510,"url":"https://github.com/infrablocks/end-to-end-openvpn","last_synced_at":"2025-07-10T06:33:05.461Z","repository":{"id":80678891,"uuid":"256055970","full_name":"infrablocks/end-to-end-openvpn","owner":"infrablocks","description":"An end-to-end example of InfraBlocks, by provisioning an OpenVPN cluster.","archived":false,"fork":false,"pushed_at":"2024-07-30T15:45:21.000Z","size":225,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-07-30T19:52:15.309Z","etag":null,"topics":["end-to-end","example","infrablocks","infrastructure","infrastructure-as-code","openvpn","openvpn-server","terraform"],"latest_commit_sha":null,"homepage":null,"language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/infrablocks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-04-15T22:59:42.000Z","updated_at":"2024-07-30T15:45:25.000Z","dependencies_parsed_at":"2023-10-31T22:23:52.230Z","dependency_job_id":null,"html_url":"https://github.com/infrablocks/end-to-end-openvpn","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infrablocks%2Fend-to-end-openvpn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infrablocks%2Fend-to-end-openvpn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infrablocks%2Fend-to-end-openvpn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infrablocks%2Fend-to-end-openvpn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/infrablocks","download_url":"https://codeload.github.com/infrablocks/end-to-end-openvpn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225622825,"owners_count":17498170,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["end-to-end","example","infrablocks","infrastructure","infrastructure-as-code","openvpn","openvpn-server","terraform"],"created_at":"2024-11-20T20:16:34.651Z","updated_at":"2024-11-20T20:16:36.813Z","avatar_url":"https://github.com/infrablocks.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"End to End Example - OpenVPN\n============================\n\nThis is an end-to-end deployment of a single infrastructure component, in this\ncase it's an OpenVPN server. We combine several tools to make this work:\n\n* Rake - for task management\n* Terraform - for infrastructure provisioning, heavily leaning on InfraBlocks\n* Confidante - for configuration management\n\nConcepts\n--------\n\nInfraBlocks modules, and our configuration, contain some terms which need\nexplanation:\n\n### Component\n\nA collection of infrastructure, which together provides value. For example, a\ntypical micro-service to serve customer information, with a database and an ECS\nService, would all come under the component `customer-service`. For this \ncodebase, we've just used `openvpn-example`, but this could easily be \n`vpn-server`.\n\n### Role\n\nThe individual bits that make up a component. Examples of roles include the \n`database`, `log-group`, and the `service`. You can see how we layer together\nroles in the `config/roles` directory.\n\n### Deployment Identifier\n\nA label so you can differentiate between multiple deployments of the same \ncomponent. This could be tied to an environment, e.g. `development` or \n`production`, or something more clever. We've used a mixture of environment and\nbuild flavours, so we could run A/B tests of services, e.g. `production-blue`\nand `production-green`.\n\nDeployment\n----------\n\nThis code requires terraform 0.12 or greater.\n\n### Set up your machine (optional)\n\nWe use the `go` script to automate pre-install steps like installing Gems. To \nget `go` onto the PATH, we use direnv. If you want to skip this step, use `rake` \ninstead of `go` in all the commands below.\n\n```shell script\nbrew install direnv\ndirenv allow\n```\n\n### Unlock the secrets\n\nIt's not recommended, but for this example we keep secrets in the repository.\n\nWe keep them locked up using `git-crypt` which uses GPG keys to allow access\nto specific users. However, for the purposes of this example repository, \nwe've exported the symmetric keys and committed them so that you can unlock \nthe secrets.\n\n```shell script\nbrew install git-crypt\n```\n\nTo securely manage the VPN, we are using two different secrets access roles, \nan \"operator\" and a \"user\" (the default):\n\n- Operators are responsible for managing the public key infrastructure (PKI), \n  and provisioning certificates for VPN clients and servers.\n- Users are the clients of the VPN and are able to access their encrypted VPN\n  profiles.   \n\nTo unlock the secrets for a user:\n\n```shell script\ngit-crypt unlock ./git-crypt-default-key\n```\n\nTo unlock the secrets for an operator:\n\n```shell script\ngit-crypt unlock ./git-crypt-operator-key\n```\n\n**If you want to deploy this for real:**\n\n- Reset git-crypt and use GPG keys to manage access for each of the roles\n- Recreate all the secrets from scratch\n\nSee the [Operation](#operation) section for instructions on how to do this. \n\n### Choose a deployment identifier\n\nBecause S3 buckets are global, if you deployed this all as-is you'd likely bump\ninto others (including us!) for things like S3 buckets. So you need to change\nthe deployment identifier.\n\nIt can be anything you want. :-)\n\n```shell script\nexport DEPLOYMENT_IDENTIFIER=example\n```\n\n### Provision the state bucket\n\nWe need to store remote terraform state, so the first thing we do is build an S3\nbucket to keep it all in.\n\n```shell script\ngo \"bucket:provision[$DEPLOYMENT_IDENTIFIER]\"\n```\n\nThe state for this bucket is stored in the `state` folder in this repository.\n\nIf you want to use this repository as part of a team environment, you need to go\ninto the `.gitignore` file and delete the following:\n\n```shell script\n# State bucket state - remove this\nstate/*\n```\n\n### Provision the DNS zone\n\nIn this example, we stand up a public and private zone so we can refer to our\nCI by name rather than by IP address.\n\n```shell script\ngo \"domain:provision[$DEPLOYMENT_IDENTIFIER,example.com]\"\n```\n\n### Provision the network\n\nWe need to build a network to put our services into. At the moment it just takes\nup `10.0.0.0/16`.\n\n```shell script\ngo \"network:provision[$DEPLOYMENT_IDENTIFIER]\"\n```\n\n### Provision the ECS cluster\n\nWe need to provision some machines to run our ECS cluster on. In this example\nwe spin up a single `t2.medium` box per availability zone. In this case, it's\nthree.\n\n```shell script\ngo \"cluster:provision[$DEPLOYMENT_IDENTIFIER]\"\n```\n\n### Provision the VPN service\n\nOnce we have everything we need, now we just need to tell ECS to deploy the\nVPN service. This will give us an ECS service, as well as a load balancer.\n\nNote: In this example, we've opened up VPN access to `0.0.0.0/0`.\n\n```shell script\ngo \"service:provision[$DEPLOYMENT_IDENTIFIER]\"\n```\n\nOperation\n---------\n\n### Secrets management\n\nIf you plan to deploy the VPN yourself, you must reset the `git-crypt` \nconfiguration for this repository and recreate all secrets.\n\n#### Reset `git-crypt` configuration\n\nResetting `git-crypt` for the repository requires:\n\n* removing all managed secrets;\n* removing all authorised users; and \n* removing any symmetric keys.\n\n```shell script\nrm -rf \\\n  config/secrets \\\n  .git-crypt \\\n  .git/git-crypt\n```\n\nAfter deleting secrets and `git-crypt` configuration, commit the changes.\n\nRe-initialising `git-crypt` for the repository requires:\n\n* initialising the default key;\n* initialising the operator key; and\n* adding user GPG keys for each of the secrets access roles;\n\n```shell script\ngit-crypt init\ngit-crypt init -k operator\ngit-crypt add-gpg-user \u003ckey-id-of-user\u003e\ngit-crypt add-gpg-user -k operator \u003ckey-id-of-operator\u003e\ngit-crypt unlock\n```\n\nNote: an operator can also be a user by adding their GPG key to the default\nand operator keys.\n\n#### Recreate all secrets\n\nWe typically include a `.unlocked` file in the secrets directory so that we can\ncheck, programmatically or otherwise, whether secrets are unlocked.\n\n```shell script\nmkdir -p config/secrets\necho \"true\" \u003e config/secrets/.unlocked\n```\n\nWhen we deploy the ECS cluster for the VPN server, we provide an SSH key\nallowing access to the cluster container instances, which is stored in\n`config/secrets/cluster/`. We use a Rake task to generate this key.\n\n```shell script\ngo \"cluster_key:generate\"\n```\n\nThe only other secrets that need re-creating are for the PKI. See \n[PKI management](#pki-management) below for more details. \n\n### PKI management\n\nOpenVPN requires a PKI to manage VPN clients and servers. We use a set of Rake\ntasks to administer the PKI, stored in `config/secrets/pki`, securely. These \nRake tasks should be run by an operator with `git-crypt` unlocked as they \nupdate the encrypted PKI.\n\n#### Generate a new PKI\n\nTo generate a new PKI, including the root certificate authority (CA) \ncertificate, Diffie-Hellman (DH) parameters and a certificate revocation list \n(CRL):\n\n```\n$ go \"pki:generate\"\n```\n\n#### Manage server keys and certificates\n\nTo generate a key and certificate for a VPN server:\n\n```\n$ go \"server:generate[\u003cdns-address-of-server\u003e]\"\n```\n\nTo revoke a VPN server certificate:\n\n```\n$ go \"server:revoke[\u003cdns-address-of-server\u003e]\"\n```\n\n#### Manage client profiles\n\nWe generate full `.ovpn` profiles for clients of the VPN and store them \nencrypted with the user's GPG key in the `config/secrets/openvpn` directory.\nThe Rake tasks assume the user's public GPG key is available at \n`config/gpg/\u003cuser-email-address\u003e.gpgkey` so make sure it's available before \nrunning these commands.\n\nTo add a new client to the VPN:\n\n```\n$ go \"client:add[\u003cuser-email-address\u003e,\u003cvpn-dns-address\u003e]\"\n``` \n\nTo remove a client from the VPN:\n\n```\n$ go \"client:remove[\u003cuser-email-address\u003e]\"\n```\n\n### Advanced configuration\n\n#### Push additional routes\n\nIn some instances, we'll want all traffic for a given third party to go through\nthe VPN such that it originates from the NAT gateway rather from our \ndevelopment machines. This is common in the case where IP whitelisting is\nused by those 3rd parties.\n\nOpenVPN supports pushing specific routes to the client on connection. The\n3rd party server address can be expressed as a DNS name or as an IP address. In\nthe case of a DNS name, OpenVPN resolves the DNS name and pushes the resulting\nIP address down to the client.\n\nTo add additional pushed routes, see `src/openvpn/server.conf.additional`. The\ncontents of this file are appended to the server configuration on container\nstart-up so any other OpenVPN configuration can be added here also.\n\nUsage\n-----\n\nTo get set up as a user of the VPN:\n\n1. Add your GPG key to the `config/gpg` directory as \n`\u003cyour-email-address\u003e.gpgkey`.\n2. Ask an operator to create your profile.\n3. Decrypt your profile and add to your VPN client:\n\n```\ngpg -d config/secrets/openvpn/\u003cyour-email-address\u003e.ovpn.gpg \u003e profile.ovpn\nopen profile.ovpn\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfrablocks%2Fend-to-end-openvpn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finfrablocks%2Fend-to-end-openvpn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfrablocks%2Fend-to-end-openvpn/lists"}