diff --git a/docs/source/reference/1-commcare-cloud/commands.md b/docs/source/reference/1-commcare-cloud/commands.md index dbf9293902..34b60ca8fb 100644 --- a/docs/source/reference/1-commcare-cloud/commands.md +++ b/docs/source/reference/1-commcare-cloud/commands.md @@ -1693,60 +1693,6 @@ have been made to our actual resources in AWS. --- -#### ``openvpn-activate-user`` Command - -Give a OpenVPN user a temporary password (the ansible user password) - -``` -commcare-cloud openvpn-activate-user [--use-factory-auth] vpn_user -``` - -to allow the user to connect to the VPN, log in, and change their password using - -``` -cchq openvpn-claim-user -``` - -##### Positional Arguments - -###### `vpn_user` - -The user to activate. - -Must be one of the defined ssh users defined for the environment. - -##### Options - -###### `--use-factory-auth` - -authenticate using the pem file (or prompt for root password if there is no pem file) - ---- - -#### ``openvpn-claim-user`` Command - -Claim an OpenVPN user as your own, setting its password - -``` -commcare-cloud openvpn-claim-user [--use-factory-auth] vpn_user -``` - -##### Positional Arguments - -###### `vpn_user` - -The user to claim. - -Must be one of the defined ssh users defined for the environment. - -##### Options - -###### `--use-factory-auth` - -authenticate using the pem file (or prompt for root password if there is no pem file) - ---- - #### ``forward-port`` Command Port forward to access a remote admin console diff --git a/environments/india/terraform.yml b/environments/india/terraform.yml index c03f35be11..1890924050 100644 --- a/environments/india/terraform.yml +++ b/environments/india/terraform.yml @@ -15,7 +15,6 @@ az_codes: - c vpc_begin_range: "10.203" -openvpn_image: ami-085d67fbfe42a25e7 vpn_connections: [] diff --git a/environments/production/terraform.yml b/environments/production/terraform.yml index 9f97653234..11cdf689cd 100644 --- a/environments/production/terraform.yml +++ b/environments/production/terraform.yml @@ -11,7 +11,6 @@ azs: - "us-east-1c" vpc_begin_range: "10.202" -openvpn_image: ami-5e73b923 ec2_metadata_tokens_required: yes diff --git a/environments/staging/terraform.yml b/environments/staging/terraform.yml index 79a9016faf..5a79f39749 100644 --- a/environments/staging/terraform.yml +++ b/environments/staging/terraform.yml @@ -11,7 +11,6 @@ azs: - "us-east-1c" vpc_begin_range: "10.201" -openvpn_image: ami-5e73b923 backup_plan: local_vault_name: "BusinessContinuity_Staging_East-1" diff --git a/src/commcare_cloud/ansible/host_group_aliases.yml b/src/commcare_cloud/ansible/host_group_aliases.yml index fed09609b9..19f6b47492 100644 --- a/src/commcare_cloud/ansible/host_group_aliases.yml +++ b/src/commcare_cloud/ansible/host_group_aliases.yml @@ -6,7 +6,6 @@ hostname: "{{ item }}" groups: all_commcarehq with_items: "{{ groups['all'] }}" - when: "item not in groups['openvpn']|default([])" changed_when: no - name: Create commcarehq group alias add_host: diff --git a/src/commcare_cloud/ansible/openvpn_playbooks/activate_vpn_user.yml b/src/commcare_cloud/ansible/openvpn_playbooks/activate_vpn_user.yml deleted file mode 100644 index de612cf570..0000000000 --- a/src/commcare_cloud/ansible/openvpn_playbooks/activate_vpn_user.yml +++ /dev/null @@ -1,15 +0,0 @@ -- name: Activate VPN User - hosts: openvpn - tasks: - - name: "Assert that {{ vpn_user }} already exists" - assert: - that: "vpn_user in dev_users.present" - fail_msg: "Cannot activate {{ vpn_user }} because user does not exist. User must be in dev_users." - - name: "Set {{ vpn_user }} to temporary password" - become: yes - user: - name: "{{ vpn_user }}" - password: "{{ ansible_sudo_pass | password_hash('sha512') }}" - - name: "Auto-expire after a day if they don't reset password" - become: yes - shell: "passwd {{ vpn_user }} -x 1" diff --git a/src/commcare_cloud/ansible/openvpn_playbooks/create_openvpn_cert.yml b/src/commcare_cloud/ansible/openvpn_playbooks/create_openvpn_cert.yml deleted file mode 100644 index 31fadb14c0..0000000000 --- a/src/commcare_cloud/ansible/openvpn_playbooks/create_openvpn_cert.yml +++ /dev/null @@ -1,30 +0,0 @@ -- name: Create OpenVPN Cert - hosts: openvpn - tasks: - - name: Configure HTTPS Cert - become: yes - # this was copy-paste-modified from - # https://github.com/lmammino/terraform-openvpn/blob/792ca775b308386816d0f74113e1b6d38c784d1c/main.tf#L206-L214 - # and - # https://certbot.eff.org/lets-encrypt/ubuntuxenial-other - shell: | - apt-get -y update - apt-get -y install software-properties-common - add-apt-repository -y ppa:certbot/certbot - apt-get -y update - apt-get -y install certbot - service openvpnas stop - certbot certonly --standalone --non-interactive --agree-tos --email {{ certificate_email }} --domains {{ subdomain_name }} --pre-hook 'service openvpnas stop' --post-hook 'service openvpnas start' - ln -s -f /etc/letsencrypt/live/{{ subdomain_name }}/cert.pem /usr/local/openvpn_as/etc/web-ssl/server.crt - ln -s -f /etc/letsencrypt/live/{{ subdomain_name }}/privkey.pem /usr/local/openvpn_as/etc/web-ssl/server.key - service openvpnas start - - - name: Add certbot cron - become: yes - cron: - name: "Certbot Renew" - job: "test -x /usr/bin/certbot && perl -e 'sleep int(rand(3600))' && certbot -q renew --renew-hook 'service openvpnas restart'" - minute: "0" - hour: "0/12" - user: root - cron_file: certbot diff --git a/src/commcare_cloud/ansible/openvpn_playbooks/mark_vpn_user_claimed.yml b/src/commcare_cloud/ansible/openvpn_playbooks/mark_vpn_user_claimed.yml deleted file mode 100644 index a427a59cb1..0000000000 --- a/src/commcare_cloud/ansible/openvpn_playbooks/mark_vpn_user_claimed.yml +++ /dev/null @@ -1,21 +0,0 @@ -- name: Mark VPN User Claimed - hosts: openvpn - tasks: - - name: "Assert that {{ vpn_user }} already exists" - assert: - that: "vpn_user in dev_users.present" - fail_msg: "Cannot activate {{ vpn_user }} because user does not exist. User must be in dev_users." - - name: "Assert that the password is 24 characters or longer" - assert: - that: vpn_user_password|length >= 24 - - name: "Set {{ vpn_user }} password" - become: yes - user: - name: "{{ vpn_user }}" - password: "{{ vpn_user_password | password_hash('sha512') }}" - - name: "Revoke any auto-expiration" - become: yes - shell: "passwd {{ vpn_user }} -x -1" - vars_prompt: - - name: vpn_user_password - prompt: "Please use your Password Manager to randomly generate a new password 24 characters or longer\nEnter new VPN password" diff --git a/src/commcare_cloud/commands/terraform/openvpn.py b/src/commcare_cloud/commands/terraform/openvpn.py deleted file mode 100644 index 17cb5b5745..0000000000 --- a/src/commcare_cloud/commands/terraform/openvpn.py +++ /dev/null @@ -1,53 +0,0 @@ -from __future__ import absolute_import -from __future__ import unicode_literals -from commcare_cloud.commands.ansible.ansible_playbook import run_ansible_playbook, \ - AnsiblePlaybook, _AnsiblePlaybookAlias -from commcare_cloud.commands.command_base import CommandBase, Argument -from commcare_cloud.commands.inventory_lookup.inventory_lookup import Ssh -from commcare_cloud.environment.main import get_environment - - -class OpenvpnActivateUser(_AnsiblePlaybookAlias): - command = 'openvpn-activate-user' - help = """ - Give a OpenVPN user a temporary password (the ansible user password) - - to allow the user to connect to the VPN, log in, and change their password using - - ``` - cchq openvpn-claim-user - ``` - """ - - arguments = _AnsiblePlaybookAlias.arguments + ( - Argument('vpn_user', help=""" - The user to activate. - - Must be one of the defined ssh users defined for the environment. - """), - ) - - def run(self, args, unknown_args): - args.playbook = 'openvpn_playbooks/activate_vpn_user.yml' - unknown_args += ('-e', 'vpn_user={}'.format(args.vpn_user)) - return AnsiblePlaybook(self.parser).run(args, unknown_args, always_skip_check=True) - - -class OpenvpnClaimUser(_AnsiblePlaybookAlias): - command = 'openvpn-claim-user' - help = """ - Claim an OpenVPN user as your own, setting its password - """ - - arguments = _AnsiblePlaybookAlias.arguments + ( - Argument('vpn_user', help=""" - The user to claim. - - Must be one of the defined ssh users defined for the environment. - """), - ) - - def run(self, args, unknown_args): - args.playbook = 'openvpn_playbooks/mark_vpn_user_claimed.yml' - unknown_args += ('-e', 'vpn_user={}'.format(args.vpn_user)) - return AnsiblePlaybook(self.parser).run(args, unknown_args, always_skip_check=True) diff --git a/src/commcare_cloud/commands/terraform/templates/variables.tf.j2 b/src/commcare_cloud/commands/terraform/templates/variables.tf.j2 index b661cf5a1d..9bac1205c7 100644 --- a/src/commcare_cloud/commands/terraform/templates/variables.tf.j2 +++ b/src/commcare_cloud/commands/terraform/templates/variables.tf.j2 @@ -10,15 +10,7 @@ variable "vpc_begin_range" {} # OptInRequired: In order to use this AWS Marketplace product you need to accept terms and subscribe. # To do so please visit http://aws.amazon.com/marketplace/pp?sku=3ihdqli79gl9v2jnlzs6nq60h -variable "openvpn_image" { - default = "" # will be auto-assigned by openvpn module if not set -} -variable "openvpn_instance_type" { - default = "t2.small" -} -variable "openvpn_az" { - default = "a" -} + data "aws_ami" "ubuntu_bionic" { # Should match what is in diff --git a/src/commcare_cloud/commcare_cloud.py b/src/commcare_cloud/commcare_cloud.py index 8b0e13b4be..94554217cb 100644 --- a/src/commcare_cloud/commcare_cloud.py +++ b/src/commcare_cloud/commcare_cloud.py @@ -23,7 +23,6 @@ from commcare_cloud.commands.secrets import Secrets, MigrateSecrets from commcare_cloud.commands.sentry import ExportSentryEvents from commcare_cloud.commands.terraform.aws import AwsList, AwsFillInventory, AwsSignIn -from commcare_cloud.commands.terraform.openvpn import OpenvpnActivateUser, OpenvpnClaimUser from commcare_cloud.commands.terraform.terraform import Terraform from commcare_cloud.commands.terraform.terraform_migrate_state import TerraformMigrateState from commcare_cloud.commands.validate_environment_settings import ValidateEnvironmentSettings @@ -104,8 +103,6 @@ AwsSignIn, AwsList, AwsFillInventory, - OpenvpnActivateUser, - OpenvpnClaimUser, ForwardPort, ]) ]) diff --git a/src/commcare_cloud/environment/schemas/terraform.py b/src/commcare_cloud/environment/schemas/terraform.py index ef82e72db2..da023e4b14 100644 --- a/src/commcare_cloud/environment/schemas/terraform.py +++ b/src/commcare_cloud/environment/schemas/terraform.py @@ -21,9 +21,6 @@ class TerraformConfig(jsonobject.JsonObject): state_bucket_region = jsonobject.StringProperty() region = jsonobject.StringProperty() environment = jsonobject.StringProperty() - openvpn_image = jsonobject.StringProperty() - openvpn_instance_type = jsonobject.StringProperty() - openvpn_az = jsonobject.StringProperty() azs = jsonobject.ListProperty(str) az_codes = jsonobject.ListProperty(str, default=['a', 'b', 'c']) ssl_policy = jsonobject.StringProperty(default="ELBSecurityPolicy-2016-08") diff --git a/src/commcare_cloud/terraform/README.md b/src/commcare_cloud/terraform/README.md index f6f13d3ac1..37c25d5370 100644 --- a/src/commcare_cloud/terraform/README.md +++ b/src/commcare_cloud/terraform/README.md @@ -64,163 +64,3 @@ You can run terraform with ``` cchq terraform apply ``` - -Because of a slight defect in our code, if you're using a site-to-site VPN -as configured through `vpn_connections` and `external_routes` in `terraform.yml`, -you have to hard-code VPN Gateway in `external_routes`. This means that first you have to -run terraform (to create the gateway), look up its id at -https://console.aws.amazon.com/vpc/home?#VpnGateways:sort=VpnGatewayId, -and edit `external_routes` to -hardcode the gateway, and then run terraform again. - -## VPN Setup - -### Create the OpenVPN EC2 instance with Terraform -The first time you run `cchq terraform apply`, -it will fail with a link to a terms of service you need to accept. -To do so: -1. First, make sure you are logged into https://console.aws.amazon.com/console/home - _under the correct account_. - (Each environment is it's own linked account, - so be careful you're not logged into the - e.g. staging account if you're doing this for production) -2. Then click on the link in the output -3. Accept the terms and click "Continue to Subscribe". - - -### Gain temporary SSH access via your own IP -Once the VM is created, you still need to create a VPN user before you can use the VPN. -To do this, go into the console, find the vpn ec2 instance, go to its security group, -and click Inbound Traffic > Edit > Add Rule. Select Type "SSH" and Source "My IP", -and click Save. - -Now you will be able to SSH into the VM. - -To make a cert, you'll also need to open port 80, so click Add Rule again, -select Type HTTP, **Source "Anywhere"** (needs to be publicly accessible), -and click Save. - -Finally, make sure to run - -```bash -cchq aws-fill-inventory -``` - -which will auto-generate an `[openvpn]` section to your inventory.ini. -For this to work, make sure you're using the inventory templating style. If you aren't, -you can just move `inventory.ini` to `inventory.ini.j2` before running that command, -and it'll generate `inventory.ini` for you. You can (can should) commit `inventory.ini`. - -In order to log in from the public IP address, you'll need to uncomment the ansible_host -variable of `[openvpn]`. (Don't commit this change with the file!) - -### Run the ovpn-init script - -``` -cchq ssh openvpnas@openvpn -sudo ovpn-init --ec2 -... -Please enter 'DELETE' to delete existing configuration:DELETE -... -Please enter 'yes' to indicate your agreement [no]: yes -... -``` -Make sure to type `yes` for the first prompt, and then just hit enter until it's done. -Then set a password with -``` -sudo passwd openvpn -``` -This is the password you'll use to enter the admin web UI. - -### Give others SSH access to the VPN machine -To give others SSH access to the VPN machine -(right now your access is because terraform created the VM with your public key) - -``` -cchq bootstrap-users --limit openvpn -u openvpnas -cchq deploy-stack --limit openvpn --skip-check -``` - -If this gives you any trouble, try ssh'ing in again and running - -``` -sudo apt update -sudo apt install python -``` - -to install python. - -### Set up DNS and HTTPS cert - -By whatever means you have, make a DNS entry that points a subdomain name -to the openvpn machine's public IP. The subdomain should be called `vpn.{{ SITE_HOST }}`, -e.g. if the site is at www.mycchqsite.org, it should be vpn.www.mycchqsite.org - -Then run -``` -cchq ansible-playbook openvpn_playbooks/create_openvpn_cert.yml --skip-check -vvv -e certificate_email=youremail@example.com -``` - -### Enable PAM in the web Admin UI - -OpenVPN has a number authentication modes, and we're going to use -[PAM](https://docs.openvpn.net/command-line/authentication-options-and-command-line-configuration/#PAM_authentication), -which make VPN usernames and passwords mirror linux system user usernames and passwords. -In PAM authentication mode, -enabling a user just requires setting their linux user's password with `passwd`. - -Go to `https:///admin` in your browser and log in with `openvpn`/``. -Then navigate to /admin/pam_configuration and click Use PAM, -and then click Update Running Server. - -### Activate your user - -To activate a user, run - -``` -cchq openvpn-activate-user -``` - -and then have the user (in this case, yourself) -claim the user and set their password with - -``` -cchq openvpn-claim-user -``` - -providing first the ansible sudo user password, and then the new (secure!) password -as prompted. - -### Connect to the VPN -Download the openvpn client and connect to the public IP with your username and password. - -### Un-whitelist SSH traffic from your IP address -Finally once you've proven you can get on the VPN and log into VMs with their private IPs, -and once you've created a cert, -run `cchq terraform apply` again to undo the temporary change you made via the console -that allowed you to SSH into the openvpn machine from the public internet, -and that allowed letsencrypt to make a request to port 80. - -From here on out if you need to ssh into the VPN machine, -you can either manually whitelist yourself again, or else you'll have to connect to the VPN -and use the VPN machine's private IP address. Note that if you are using the private IP -and you run `sudo service openvpnas stop`, it will disconnect you from the VPN and you -won't be able to connect again. Then you will be forced to whitelist your IP -and use the public IP to ssh in and bring it back up. - -Finally, re-comment the ansible_host variable of `[openvpn]` -(or just `git checkout -- ...` this change). - -### Make sure everything works - -Now that you've turned off your special access, make sure you can -log on to the VPN again and then run - -``` -cchq ssh openvpn -``` - -to make sure you can ssh onto the machine. - -All done! Now to activate the other users, you can run the steps from "Activate your user" -above as users ask for access. diff --git a/src/commcare_cloud/terraform/modules/openvpn/README.md b/src/commcare_cloud/terraform/modules/openvpn/README.md deleted file mode 100644 index b9b71861e4..0000000000 --- a/src/commcare_cloud/terraform/modules/openvpn/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Terraform-IaC-VPN -Terraform Module to install OpenVPN server diff --git a/src/commcare_cloud/terraform/modules/openvpn/main.tf b/src/commcare_cloud/terraform/modules/openvpn/main.tf deleted file mode 100644 index 95fdf2e9ed..0000000000 --- a/src/commcare_cloud/terraform/modules/openvpn/main.tf +++ /dev/null @@ -1,137 +0,0 @@ -# This module will build out an initial OpenVPN server. - -resource "aws_instance" "vpn_host" { - ami = local.openvpn_image - instance_type = var.vpn_size - subnet_id = var.instance_subnet - key_name = var.key_name - vpc_security_group_ids = [aws_security_group.openvpn-access-sg.id] - source_dest_check = false - user_data = <<-EOF - #!/bin/bash - hostnamectl set-hostname "vpn-${var.environment}" - yum update -y - reboot -EOF - - - disable_api_termination = true - - root_block_device { - volume_size = 40 - volume_type = "gp3" - delete_on_termination = true - } - - lifecycle { - ignore_changes = [ - root_block_device.0.volume_type, - user_data, - key_name, - iam_instance_profile, - ebs_optimized, - ] - } - - tags = { - Name = "vpn-${var.environment}" - Environment = var.environment - Group = "openvpn" - } -} - -resource "aws_eip" "vpn_ip" { - domain = "vpc" - instance = aws_instance.vpn_host.id - - tags = { - Name = "vpn-public-ip-${var.environment}" - Environment = var.environment - Group = "openvpn" - } -} - -# Security Group that allows users to connecto to OpenVPN on port 443 and administration on port 943. -resource "aws_security_group" "openvpn-access-sg" { - name = "openvpn-access-sg" - description = "Allow traffic for managing and using OpenVPN" - vpc_id = var.vpc_id - - ingress { - from_port = 1194 - to_port = 1194 - protocol = "udp" - cidr_blocks = ["0.0.0.0/0"] - } - - ingress { - from_port = 22 - to_port = 22 - protocol = "tcp" - cidr_blocks = [var.vpc_cidr] - } - - ingress { - from_port = 943 - to_port = 943 - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] - } - - ingress { - from_port = 443 - to_port = 443 - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] - } - - // for auto-renewing certs - ingress { - from_port = 80 - to_port = 80 - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] - } - - ingress { - from_port = -1 - to_port = -1 - protocol = "icmp" - cidr_blocks = [var.vpc_cidr] - } - - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - } - - lifecycle { - ignore_changes = [ - description, - name, - ] - } -} - -######## DNS ######## -#resource "aws_route53_record" "openvpn_record" { -# zone_id = "${var.dns_zone_id}" -# name = "openvpn-ec2.${var.dns_domain}" -# type = "A" -# ttl = "3600" -# records = ["${aws_instance.vpn_host.private_ip}"] -#} -# -#resource "aws_route53_record" "openvpn-alb" { -# zone_id = "${var.dns_zone_id}" -# name = "openvpn.${var.dns_domain}" -# type = "A" -# -# alias { -# name = "${var.shared-alb-dns-name}" -# zone_id = "${var.shared-alb-zone-id}" -# evaluate_target_health = true -# } -#} diff --git a/src/commcare_cloud/terraform/modules/openvpn/outputs.tf b/src/commcare_cloud/terraform/modules/openvpn/outputs.tf deleted file mode 100644 index 80db07e8b1..0000000000 --- a/src/commcare_cloud/terraform/modules/openvpn/outputs.tf +++ /dev/null @@ -1,8 +0,0 @@ -output "openvpn-access-sg" { - value = aws_security_group.openvpn-access-sg.id -} - -output "openvpn-server-ip" { - value = aws_instance.vpn_host.private_ip -} - diff --git a/src/commcare_cloud/terraform/modules/openvpn/variables.tf b/src/commcare_cloud/terraform/modules/openvpn/variables.tf deleted file mode 100644 index f1cc87db2e..0000000000 --- a/src/commcare_cloud/terraform/modules/openvpn/variables.tf +++ /dev/null @@ -1,36 +0,0 @@ -# # Select the most recent OpenVPN AMI in a given region -data "aws_ami" "openvpn_image" { - most_recent = true - filter { - name = "virtualization-type" - values = ["hvm"] - } - owners = ["679593333241"] # Canonical -} - -variable "openvpn_image" { - default = "" -} - -variable "key_name" { -} - -variable "environment" { -} - -variable "instance_subnet" { -} - -variable "vpn_size" { -} - -variable "vpc_id" { -} - -variable "vpc_cidr" { -} - -locals { - openvpn_image = var.openvpn_image != "" ? var.openvpn_image : data.aws_ami.openvpn_image.id -} -