Skip to content

Commit

Permalink
Change default SSH port and introduce cloud-init support (trailofbits…
Browse files Browse the repository at this point in the history
…#1636)

* Change default SSH port

* Iptables to ansible_ssh_port

* Add Scaleway

* permissions and groups fixes

* update firewall docs

* SSH fixes

* add missing cloudinit to cloud-azure

* remove ansible_ssh_user from the tests

* congrats message fix
  • Loading branch information
jackivanov authored Jan 7, 2020
1 parent b66c9f5 commit d635c76
Show file tree
Hide file tree
Showing 25 changed files with 229 additions and 96 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ You can now set up clients to connect to your VPN. Proceed to [Configure the VPN
"# Local DNS resolver 172.16.0.1 #"
"# The p12 and SSH keys password for new users is XXXXXXXX #"
"# The CA key password is XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #"
"# Shell access: ssh -i configs/algo.pem [email protected] #"
"# Shell access: ssh -F configs/<server_ip>/ssh_config algo #"
```
## Configure the VPN Clients
Expand Down Expand Up @@ -151,17 +151,17 @@ Depending on the platform, you may need one or multiple of the following files.

If you turned on the optional SSH tunneling role, then local user accounts will be created for each user in `config.cfg` and SSH authorized_key files for them will be in the `configs` directory (user.ssh.pem). SSH user accounts do not have shell access, cannot authenticate with a password, and only have limited tunneling options (e.g., `ssh -N` is required). This ensures that SSH users have the least access required to setup a tunnel and can perform no other actions on the Algo server.

Use the example command below to start an SSH tunnel by replacing `user` and `ip` with your own. Once the tunnel is setup, you can configure a browser or other application to use 127.0.0.1:1080 as a SOCKS proxy to route traffic through the Algo server.
Use the example command below to start an SSH tunnel by replacing `<user>` and `<ip>` with your own. Once the tunnel is setup, you can configure a browser or other application to use 127.0.0.1:1080 as a SOCKS proxy to route traffic through the Algo server.

`ssh -D 127.0.0.1:1080 -f -q -C -N user@ip -i configs/<server_ip>/ssh-tunnel/<user>.pem`
`ssh -D 127.0.0.1:1080 -f -q -C -N <user>@algo -i configs/<ip>/ssh-tunnel/<user>.pem -F configs/<ip>/ssh_config`

## SSH into Algo Server

Your Algo server is configured for key-only SSH access for administrative purposes. Open the Terminal app, `cd` into the `algo-master` directory where you originally downloaded Algo, and then use the command listed on the success message:

`ssh -i configs/algo.pem user@ip`
`ssh -F configs/<ip>/ssh_config algo`

where `user` is either `root` or `ubuntu` as listed on the success message, and `ip` is the IP address of your Algo server. If you find yourself regularly logging into the server then it will be useful to load your Algo ssh key automatically. Add the following snippet to the bottom of `~/.bash_profile` to add it to your shell environment permanently.
where `<ip>` is the IP address of your Algo server. If you find yourself regularly logging into the server then it will be useful to load your Algo ssh key automatically. Add the following snippet to the bottom of `~/.bash_profile` to add it to your shell environment permanently.

`ssh-add ~/.ssh/algo > /dev/null 2>&1`

Expand Down
8 changes: 6 additions & 2 deletions config.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ users:

### Review these options BEFORE you run Algo, as they are very difficult/impossible to change after the server is deployed.

# Change default SSH port for the cloud roles only
# It doesn't apply if you deploy to your existing Ubuntu Server
ssh_port: 4160

# Deploy StrongSwan to enable IPsec support
ipsec_enabled: true

Expand Down Expand Up @@ -94,7 +98,7 @@ dns_servers:
# Supports on MacOS and Linux only (including Windows Subsystem for Linux)
pki_in_tmpfs: true

# Set this to 'true' when running './algo update-users' if you want ALL users to get new certs, not just new users.
# Set this to 'true' when running './algo update-users' if you want ALL users to get new certs, not just new users.
keys_clean_all: false

# StrongSwan log level
Expand Down Expand Up @@ -134,7 +138,7 @@ congrats:
ca_key_pass: |
"# The CA key password is {{ CA_password|default(omit) }} #"
ssh_access: |
"# Shell access: ssh -i {{ ansible_ssh_private_key_file|default(omit) }} {{ ansible_ssh_user|default(omit) }}@{{ ansible_ssh_host|default(omit) }} #"
"# Shell access: ssh -F configs/{{ ansible_ssh_host|default(omit) }}/ssh_config algo #"

SSH_keys:
comment: algo@ssh
Expand Down
2 changes: 1 addition & 1 deletion docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ No.
## What inbound ports are used?

You should only need 22/TCP, 500/UDP, 4500/UDP, and 51820/UDP opened on any firewall that sits between your clients and your Algo server. See [AlgoVPN and Firewalls](/docs/firewalls.md) for more information.
You should only need 4160/TCP, 500/UDP, 4500/UDP, and 51820/UDP opened on any firewall that sits between your clients and your Algo server. See [AlgoVPN and Firewalls](/docs/firewalls.md) for more information.

## How do I monitor user activity?

Expand Down
2 changes: 1 addition & 1 deletion docs/firewalls.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Any external firewall must be configured to pass the following incoming ports ov

Port | Protocol | Description | Related variables in `config.cfg`
---- | -------- | ----------- | ---------------------------------
22 | TCP | Secure Shell (SSH) | None
4160 | TCP | Secure Shell (SSH) | `ssh_port`
500 | UDP | IPsec IKEv2 | `ipsec_enabled`
4500 | UDP | IPsec NAT-T | `ipsec_enabled`
51820 | UDP | WireGuard | `wireguard_enabled`, `wireguard_port`
Expand Down
19 changes: 19 additions & 0 deletions files/cloud-init/base.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash
set -eux

apt-get update -y
apt-get install sudo -y

getent passwd algo || useradd -m -d /home/algo -s /bin/bash -G adm,netdev -p '!' algo

(umask 337 && echo "algo ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/10-algo-user)

cat <<EOF >/etc/ssh/sshd_config
{{ lookup('template', 'files/cloud-init/sshd_config') }}
EOF

test -d /home/algo/.ssh || (umask 077 && sudo -u algo mkdir -p /home/algo/.ssh/)
echo "{{ lookup('file', '{{ SSH_keys.public }}') }}" | (umask 177 && sudo -u algo tee /home/algo/.ssh/authorized_keys)

sudo apt-get remove -y --purge sshguard || true
systemctl restart sshd.service
29 changes: 29 additions & 0 deletions files/cloud-init/base.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#cloud-config
output: {all: '| tee -a /var/log/cloud-init-output.log'}

package_update: true
package_upgrade: true

packages:
- sudo

users:
- default
- name: algo
homedir: /home/algo
sudo: ALL=(ALL) NOPASSWD:ALL
groups: adm,netdev
shell: /bin/bash
lock_passwd: true
ssh_authorized_keys:
- "{{ lookup('file', '{{ SSH_keys.public }}') }}"

write_files:
- path: /etc/ssh/sshd_config
content: |
{{ lookup('template', 'files/cloud-init/sshd_config') | indent(width=6) }}
runcmd:
- set -x
- sudo apt-get remove -y --purge sshguard || true
- systemctl restart sshd.service
10 changes: 10 additions & 0 deletions files/cloud-init/sshd_config
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Port {{ ssh_port }}
AllowGroups algo
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
13 changes: 8 additions & 5 deletions playbooks/cloud-post.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
name: "{% if cloud_instance_ip == 'localhost' %}localhost{% else %}{{ cloud_instance_ip }}{% endif %}"
groups: vpn-host
ansible_connection: "{% if cloud_instance_ip == 'localhost' %}local{% else %}ssh{% endif %}"
ansible_ssh_user: "{{ ansible_ssh_user }}"
ansible_ssh_user: "{{ ansible_ssh_user|default('root') }}"
ansible_ssh_port: "{{ ansible_ssh_port|default(22) }}"
ansible_python_interpreter: "/usr/bin/python3"
algo_provider: "{{ algo_provider }}"
algo_server_name: "{{ algo_server_name }}"
Expand All @@ -19,6 +20,7 @@
algo_ssh_tunneling: "{{ algo_ssh_tunneling }}"
algo_store_pki: "{{ algo_store_pki }}"
IP_subject_alt_name: "{{ IP_subject_alt_name }}"
cloudinit: "{{ cloudinit|default(false) }}"

- name: Additional variables for the server
add_host:
Expand All @@ -28,7 +30,7 @@

- name: Wait until SSH becomes ready...
wait_for:
port: 22
port: "{{ ansible_ssh_port|default(22) }}"
host: "{{ cloud_instance_ip }}"
search_regex: "OpenSSH"
delay: 10
Expand All @@ -47,6 +49,7 @@
- debug:
var: IP_subject_alt_name

- name: A short pause, in order to be sure the instance is ready
pause:
seconds: 20
- name: Wait 600 seconds for target connection to become reachable/usable
wait_for_connection:
delegate_to: "{{ item }}"
loop: "{{ groups['vpn-host'] }}"
15 changes: 11 additions & 4 deletions roles/cloud-azure/files/deployment.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
},
"imageReferenceSku": {
"type": "string"
},
"SshPort": {
"type": "int"
},
"UserData": {
"type": "string"
}
},
"variables": {
Expand All @@ -30,10 +36,10 @@
{
"name": "AllowSSH",
"properties": {
"description": "Locks inbound down to ssh default port 22.",
"description": "Allow SSH",
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"destinationPortRange": "[parameters('SshPort')]",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
Expand Down Expand Up @@ -160,13 +166,14 @@
},
"osProfile": {
"computerName": "[resourceGroup().name]",
"adminUsername": "ubuntu",
"customData": "[parameters('UserData')]",
"adminUsername": "algo",
"linuxConfiguration": {
"disablePasswordAuthentication": true,
"ssh": {
"publicKeys": [
{
"path": "/home/ubuntu/.ssh/authorized_keys",
"path": "/home/algo/.ssh/authorized_keys",
"keyData": "[parameters('sshKeyData')]"
}
]
Expand Down
8 changes: 7 additions & 1 deletion roles/cloud-azure/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@
value: "{{ cloud_providers.azure.size }}"
imageReferenceSku:
value: "{{ cloud_providers.azure.image }}"
SshPort:
value: "{{ ssh_port }}"
UserData:
value: "{{ lookup('template', 'files/cloud-init/base.yml') | b64encode }}"
register: azure_rm_deployment

- set_fact:
cloud_instance_ip: "{{ azure_rm_deployment.deployment.outputs.publicIPAddresses.value }}"
ansible_ssh_user: ubuntu
ansible_ssh_user: algo
ansible_ssh_port: "{{ ssh_port }}"
cloudinit: true
15 changes: 5 additions & 10 deletions roles/cloud-cloudstack/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,38 +26,33 @@
end_port: "{{ item.end_port }}"
cidr: "{{ item.range }}"
with_items:
- { proto: tcp, start_port: 22, end_port: 22, range: 0.0.0.0/0 }
- { proto: tcp, start_port: '{{ ssh_port }}', end_port: '{{ ssh_port }}', range: 0.0.0.0/0 }
- { proto: udp, start_port: 4500, end_port: 4500, range: 0.0.0.0/0 }
- { proto: udp, start_port: 500, end_port: 500, range: 0.0.0.0/0 }
- { proto: udp, start_port: "{{ wireguard_port }}", end_port: "{{ wireguard_port }}", range: 0.0.0.0/0 }

- name: Keypair created
cs_sshkeypair:
name: "{{ SSH_keys.comment|regex_replace('@', '_') }}"
public_key: "{{ lookup('file', '{{ SSH_keys.public }}') }}"
register: cs_keypair

- name: Set facts
set_fact:
image_id: "{{ cloud_providers.cloudstack.image }}"
size: "{{ cloud_providers.cloudstack.size }}"
disk: "{{ cloud_providers.cloudstack.disk }}"
keypair_name: "{{ cs_keypair.name }}"

- name: Server created
cs_instance:
name: "{{ algo_server_name }}"
root_disk_size: "{{ disk }}"
template: "{{ image_id }}"
ssh_key: "{{ keypair_name }}"
security_groups: "{{ cs_security_group.name }}"
zone: "{{ algo_region }}"
service_offering: "{{ size }}"
user_data: "{{ lookup('template', 'files/cloud-init/base.yml') }}"
register: cs_server

- set_fact:
cloud_instance_ip: "{{ cs_server.default_ip }}"
ansible_ssh_user: ubuntu
ansible_ssh_user: algo
ansible_ssh_port: "{{ ssh_port }}"
cloudinit: true
environment:
CLOUDSTACK_CONFIG: "{{ algo_cs_config }}"
CLOUDSTACK_REGION: "{{ algo_cs_region }}"
5 changes: 4 additions & 1 deletion roles/cloud-digitalocean/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@
unique_name: true
ipv6: true
ssh_keys: "{{ do_ssh_key.data.ssh_key.id }}"
user_data: "{{ lookup('template', 'files/cloud-init/base.yml') }}"
tags:
- Environment:Algo
register: digital_ocean_droplet

- set_fact:
cloud_instance_ip: "{{ digital_ocean_droplet.data.ip_address }}"
ansible_ssh_user: root
ansible_ssh_user: algo
ansible_ssh_port: "{{ ssh_port }}"
cloudinit: true
28 changes: 7 additions & 21 deletions roles/cloud-ec2/files/stack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Parameters:
Default: ''
EbsEncrypted:
Type: String
UserData:
Type: String
SshPort:
Type: String
Conditions:
AllocateNewEIP: !Equals [!Ref UseThisElasticIP, '']
AssociateExistingEIP: !Not [!Equals [!Ref UseThisElasticIP, '']]
Expand Down Expand Up @@ -123,8 +127,8 @@ Resources:
GroupDescription: Enable SSH and IPsec
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
FromPort: !Ref SshPort
ToPort: !Ref SshPort
CidrIp: 0.0.0.0/0
- IpProtocol: udp
FromPort: '500'
Expand All @@ -148,16 +152,6 @@ Resources:
- SubnetIPv6
- Subnet
- InstanceSecurityGroup
Metadata:
AWS::CloudFormation::Init:
config:
files:
/home/ubuntu/.ssh/authorized_keys:
content:
Ref: PublicSSHKeyParameter
mode: "000644"
owner: "ubuntu"
group: "ubuntu"
Properties:
InstanceType:
Ref: InstanceTypeParameter
Expand All @@ -174,15 +168,7 @@ Resources:
Ref: ImageIdParameter
SubnetId: !Ref Subnet
Ipv6AddressCount: 1
UserData:
"Fn::Base64":
!Sub |
#!/bin/bash -xe
apt-get update
apt-get -y install python-pip
pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz
cfn-init -v --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region}
cfn-signal -e $? --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region}
UserData: !Ref UserData
Tags:
- Key: Name
Value: !Ref AWS::StackName
Expand Down
2 changes: 2 additions & 0 deletions roles/cloud-ec2/tasks/cloudformation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
WireGuardPort: "{{ wireguard_port }}"
UseThisElasticIP: "{{ existing_eip }}"
EbsEncrypted: "{{ encrypted }}"
UserData: "{{ lookup('template', 'files/cloud-init/base.yml') | b64encode }}"
SshPort: "{{ ssh_port }}"
tags:
Environment: Algo
register: stack
4 changes: 3 additions & 1 deletion roles/cloud-ec2/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@

- set_fact:
cloud_instance_ip: "{{ stack.stack_outputs.ElasticIP }}"
ansible_ssh_user: ubuntu
ansible_ssh_user: algo
ansible_ssh_port: "{{ ssh_port }}"
cloudinit: true
12 changes: 6 additions & 6 deletions roles/cloud-gce/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
- '{{ wireguard_port|string }}'
- ip_protocol: tcp
ports:
- '22'
- '{{ ssh_port }}'
- ip_protocol: icmp

- block:
Expand Down Expand Up @@ -64,10 +64,8 @@
initialize_params:
source_image: "projects/ubuntu-os-cloud/global/images/family/{{ cloud_providers.gce.image }}"
metadata:
ssh-keys: "ubuntu:{{ ssh_public_key_lookup }}"
user-data: |
#!/bin/bash
sudo apt-get remove -y --purge sshguard
ssh-keys: "algo:{{ ssh_public_key_lookup }}"
user-data: "{{ lookup('template', 'files/cloud-init/base.yml') }}"
network_interfaces:
- network: "{{ gcp_compute_network }}"
access_configs:
Expand All @@ -81,4 +79,6 @@

- set_fact:
cloud_instance_ip: "{{ gcp_compute_instance.networkInterfaces[0].accessConfigs[0].natIP }}"
ansible_ssh_user: ubuntu
ansible_ssh_user: algo
ansible_ssh_port: "{{ ssh_port }}"
cloudinit: true
Loading

0 comments on commit d635c76

Please sign in to comment.