diff --git a/README.md b/README.md index eb85415e..97c95799 100644 --- a/README.md +++ b/README.md @@ -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 root@xxx.xxx.xx.xx #" + "# Shell access: ssh -F configs//ssh_config algo #" ``` ## Configure the VPN Clients @@ -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 `` and `` 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//ssh-tunnel/.pem` + `ssh -D 127.0.0.1:1080 -f -q -C -N @algo -i configs//ssh-tunnel/.pem -F configs//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//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 `` 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` diff --git a/config.cfg b/config.cfg index c5fbc4da..547b3647 100644 --- a/config.cfg +++ b/config.cfg @@ -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 @@ -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 @@ -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 diff --git a/docs/faq.md b/docs/faq.md index ff1ac6f9..c5a4149c 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -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? diff --git a/docs/firewalls.md b/docs/firewalls.md index 8feb5081..3b76fccb 100644 --- a/docs/firewalls.md +++ b/docs/firewalls.md @@ -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` diff --git a/files/cloud-init/base.sh b/files/cloud-init/base.sh new file mode 100644 index 00000000..1898384b --- /dev/null +++ b/files/cloud-init/base.sh @@ -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 </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 diff --git a/files/cloud-init/base.yml b/files/cloud-init/base.yml new file mode 100644 index 00000000..5cc03fdf --- /dev/null +++ b/files/cloud-init/base.yml @@ -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 diff --git a/files/cloud-init/sshd_config b/files/cloud-init/sshd_config new file mode 100644 index 00000000..02349ec5 --- /dev/null +++ b/files/cloud-init/sshd_config @@ -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 diff --git a/playbooks/cloud-post.yml b/playbooks/cloud-post.yml index 78eb607c..1495473c 100644 --- a/playbooks/cloud-post.yml +++ b/playbooks/cloud-post.yml @@ -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 }}" @@ -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: @@ -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 @@ -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'] }}" diff --git a/roles/cloud-azure/files/deployment.json b/roles/cloud-azure/files/deployment.json index 027e562b..bb055072 100644 --- a/roles/cloud-azure/files/deployment.json +++ b/roles/cloud-azure/files/deployment.json @@ -13,6 +13,12 @@ }, "imageReferenceSku": { "type": "string" + }, + "SshPort": { + "type": "int" + }, + "UserData": { + "type": "string" } }, "variables": { @@ -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", @@ -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')]" } ] diff --git a/roles/cloud-azure/tasks/main.yml b/roles/cloud-azure/tasks/main.yml index 9ff09257..80b72f80 100644 --- a/roles/cloud-azure/tasks/main.yml +++ b/roles/cloud-azure/tasks/main.yml @@ -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 diff --git a/roles/cloud-cloudstack/tasks/main.yml b/roles/cloud-cloudstack/tasks/main.yml index a881c838..a3a77812 100644 --- a/roles/cloud-cloudstack/tasks/main.yml +++ b/roles/cloud-cloudstack/tasks/main.yml @@ -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 }}" diff --git a/roles/cloud-digitalocean/tasks/main.yml b/roles/cloud-digitalocean/tasks/main.yml index b3815259..b41becdf 100644 --- a/roles/cloud-digitalocean/tasks/main.yml +++ b/roles/cloud-digitalocean/tasks/main.yml @@ -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 diff --git a/roles/cloud-ec2/files/stack.yaml b/roles/cloud-ec2/files/stack.yaml index 33cdde6d..661d5dcf 100644 --- a/roles/cloud-ec2/files/stack.yaml +++ b/roles/cloud-ec2/files/stack.yaml @@ -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, '']] @@ -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' @@ -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 @@ -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 diff --git a/roles/cloud-ec2/tasks/cloudformation.yml b/roles/cloud-ec2/tasks/cloudformation.yml index 27f42657..4ddc8d6a 100644 --- a/roles/cloud-ec2/tasks/cloudformation.yml +++ b/roles/cloud-ec2/tasks/cloudformation.yml @@ -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 diff --git a/roles/cloud-ec2/tasks/main.yml b/roles/cloud-ec2/tasks/main.yml index 674705ed..450b2679 100644 --- a/roles/cloud-ec2/tasks/main.yml +++ b/roles/cloud-ec2/tasks/main.yml @@ -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 diff --git a/roles/cloud-gce/tasks/main.yml b/roles/cloud-gce/tasks/main.yml index cd50fc63..ca68567e 100644 --- a/roles/cloud-gce/tasks/main.yml +++ b/roles/cloud-gce/tasks/main.yml @@ -32,7 +32,7 @@ - '{{ wireguard_port|string }}' - ip_protocol: tcp ports: - - '22' + - '{{ ssh_port }}' - ip_protocol: icmp - block: @@ -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: @@ -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 diff --git a/roles/cloud-hetzner/tasks/main.yml b/roles/cloud-hetzner/tasks/main.yml index 629e7218..cbae7c6e 100644 --- a/roles/cloud-hetzner/tasks/main.yml +++ b/roles/cloud-hetzner/tasks/main.yml @@ -22,10 +22,13 @@ state: present api_token: "{{ algo_hcloud_token }}" ssh_keys: "{{ hcloud_ssh_key.hcloud_ssh_key.name }}" + user_data: "{{ lookup('template', 'files/cloud-init/base.yml') }}" labels: Environment: algo register: hcloud_server - set_fact: cloud_instance_ip: "{{ hcloud_server.hcloud_server.ipv4_address }}" - ansible_ssh_user: root + ansible_ssh_user: algo + ansible_ssh_port: "{{ ssh_port }}" + cloudinit: true diff --git a/roles/cloud-lightsail/tasks/main.yml b/roles/cloud-lightsail/tasks/main.yml index b41feb45..0ee04b47 100644 --- a/roles/cloud-lightsail/tasks/main.yml +++ b/roles/cloud-lightsail/tasks/main.yml @@ -17,6 +17,9 @@ bundle_id: "{{ cloud_providers.lightsail.size }}" wait_timeout: "300" open_ports: + - from_port: "{{ ssh_port }}" + to_port: "{{ ssh_port }}" + protocol: tcp - from_port: 4500 to_port: 4500 protocol: udp @@ -27,15 +30,11 @@ to_port: "{{ wireguard_port }}" protocol: udp user_data: | - #!/bin/bash - mkdir -p /home/ubuntu/.ssh/ - echo "{{ lookup('file', '{{ SSH_keys.public }}') }}" >> /home/ubuntu/.ssh/authorized_keys - chown -R ubuntu: /home/ubuntu/.ssh/ - chmod 0700 /home/ubuntu/.ssh/ - chmod 0600 /home/ubuntu/.ssh/* - test + {{ lookup('template', 'files/cloud-init/base.sh') }} register: algo_instance - set_fact: cloud_instance_ip: "{{ algo_instance['instance']['public_ip_address'] }}" - ansible_ssh_user: ubuntu + ansible_ssh_user: algo + ansible_ssh_port: "{{ ssh_port }}" + cloudinit: true diff --git a/roles/cloud-openstack/tasks/main.yml b/roles/cloud-openstack/tasks/main.yml index fd451c58..e710defb 100644 --- a/roles/cloud-openstack/tasks/main.yml +++ b/roles/cloud-openstack/tasks/main.yml @@ -22,26 +22,26 @@ port_range_max: "{{ item.port_max }}" remote_ip_prefix: "{{ item.range }}" with_items: - - { proto: tcp, port_min: 22, port_max: 22, range: 0.0.0.0/0 } + - { proto: tcp, port_min: '{{ ssh_port }}', port_max: '{{ ssh_port }}', range: 0.0.0.0/0 } - { proto: icmp, port_min: -1, port_max: -1, range: 0.0.0.0/0 } - { proto: udp, port_min: 4500, port_max: 4500, range: 0.0.0.0/0 } - { proto: udp, port_min: 500, port_max: 500, range: 0.0.0.0/0 } - { proto: udp, port_min: "{{ wireguard_port }}", port_max: "{{ wireguard_port }}", range: 0.0.0.0/0 } -- name: Keypair created - os_keypair: - state: "{{ state|default('present') }}" - name: "{{ SSH_keys.comment|regex_replace('@', '_') }}" - public_key_file: "{{ SSH_keys.public }}" - register: os_keypair - - name: Gather facts about flavors os_flavor_facts: ram: "{{ cloud_providers.openstack.flavor_ram }}" - name: Gather facts about images os_image_facts: - image: "{{ cloud_providers.openstack.image }}" + +- name: Set image as a fact + set_fact: + image_id: "{{ item.id }}" + loop: "{{ openstack_image }}" + when: + - item.name == cloud_providers.openstack.image + - item.status == "active" - name: Gather facts about public networks os_networks_facts: @@ -58,8 +58,6 @@ - name: Set facts set_fact: flavor_id: "{{ (openstack_flavors | sort(attribute='ram'))[0]['id'] }}" - image_id: "{{ openstack_image['id'] }}" - keypair_name: "{{ os_keypair.key.name }}" security_group_name: "{{ os_security_group['secgroup']['name'] }}" - name: Server created @@ -68,12 +66,14 @@ name: "{{ algo_server_name }}" image: "{{ image_id }}" flavor: "{{ flavor_id }}" - key_name: "{{ keypair_name }}" security_groups: "{{ security_group_name }}" + userdata: "{{ lookup('template', 'files/cloud-init/base.yml') }}" nics: - net-id: "{{ public_network_id }}" register: os_server - set_fact: cloud_instance_ip: "{{ os_server['openstack']['public_v4'] }}" - ansible_ssh_user: ubuntu + ansible_ssh_user: algo + ansible_ssh_port: "{{ ssh_port }}" + cloudinit: true diff --git a/roles/cloud-scaleway/tasks/main.yml b/roles/cloud-scaleway/tasks/main.yml index 28524b55..75f0a3c4 100644 --- a/roles/cloud-scaleway/tasks/main.yml +++ b/roles/cloud-scaleway/tasks/main.yml @@ -21,6 +21,33 @@ {%- endfor -%}] - name: Create a server + scaleway_compute: + name: "{{ algo_server_name }}" + enable_ipv6: true + public_ip: dynamic + boot_type: local + state: present + image: "{{ images[0] }}" + organization: "{{ organization_id }}" + region: "{{ algo_region }}" + commercial_type: "{{ cloud_providers.scaleway.size }}" + wait: true + tags: + - Environment:Algo + - AUTHORIZED_KEY={{ lookup('file', SSH_keys.public)|regex_replace(' ', '_') }} + register: scaleway_compute + + - name: Patch the cloud-init + uri: + url: "https://cp-{{ region }}.scaleway.com/servers/{{ scaleway_compute.msg.id }}/user_data/cloud-init" + method: PATCH + body: "{{ lookup('template', 'files/cloud-init/base.yml') }}" + status_code: 204 + headers: + Content-Type: "text/plain" + X-Auth-Token: "{{ algo_scaleway_token }}" + + - name: Start the server scaleway_compute: name: "{{ algo_server_name }}" enable_ipv6: true @@ -44,4 +71,6 @@ - set_fact: cloud_instance_ip: "{{ algo_instance.msg.public_ip.address }}" - ansible_ssh_user: root + ansible_ssh_user: algo + ansible_ssh_port: "{{ ssh_port }}" + cloudinit: true diff --git a/roles/cloud-vultr/tasks/main.yml b/roles/cloud-vultr/tasks/main.yml index 79b51df8..ff34709c 100644 --- a/roles/cloud-vultr/tasks/main.yml +++ b/roles/cloud-vultr/tasks/main.yml @@ -3,12 +3,6 @@ import_tasks: prompts.yml - block: - - name: Upload the SSH key - vultr_ssh_key: - name: "{{ SSH_keys.comment }}" - ssh_key: "{{ lookup('file', '{{ SSH_keys.public }}') }}" - register: ssh_key - - name: Creating a firewall group vultr_firewall_group: name: "{{ algo_server_name }}" @@ -21,8 +15,8 @@ ip_version: "{{ item.ip }}" cidr: "{{ item.cidr }}" with_items: - - { protocol: tcp, port: 22, ip: v4, cidr: "0.0.0.0/0" } - - { protocol: tcp, port: 22, ip: v6, cidr: "::/0" } + - { protocol: tcp, port: "{{ ssh_port }}", ip: v4, cidr: "0.0.0.0/0" } + - { protocol: tcp, port: "{{ ssh_port }}", ip: v6, cidr: "::/0" } - { protocol: udp, port: 500, ip: v4, cidr: "0.0.0.0/0" } - { protocol: udp, port: 500, ip: v6, cidr: "::/0" } - { protocol: udp, port: 4500, ip: v4, cidr: "0.0.0.0/0" } @@ -30,9 +24,18 @@ - { protocol: udp, port: "{{ wireguard_port }}", ip: v4, cidr: "0.0.0.0/0" } - { protocol: udp, port: "{{ wireguard_port }}", ip: v6, cidr: "::/0" } + - name: Upload the startup script + vultr_startup_script: + name: algo-startup + script: | + {{ lookup('template', 'files/cloud-init/base.sh') }} + mkdir -p /var/lib/cloud/data/ || true + touch /var/lib/cloud/data/result.json + - name: Creating a server vultr_server: name: "{{ algo_server_name }}" + startup_script: algo-startup hostname: "{{ algo_server_name }}" os: "{{ cloud_providers.vultr.os }}" plan: "{{ cloud_providers.vultr.size }}" @@ -40,7 +43,6 @@ firewall_group: "{{ algo_server_name }}" state: started tag: Environment:Algo - ssh_key: "{{ ssh_key.vultr_ssh_key.name }}" ipv6_enabled: true auto_backup_enabled: false notify_activate: false @@ -48,7 +50,9 @@ - set_fact: cloud_instance_ip: "{{ vultr_server.vultr_server.v4_main_ip }}" - ansible_ssh_user: root + ansible_ssh_user: algo + ansible_ssh_port: "{{ ssh_port }}" + cloudinit: true environment: VULTR_API_CONFIG: "{{ algo_vultr_config }}" diff --git a/roles/common/templates/rules.v4.j2 b/roles/common/templates/rules.v4.j2 index 97084357..0f5bfba5 100644 --- a/roles/common/templates/rules.v4.j2 +++ b/roles/common/templates/rules.v4.j2 @@ -64,8 +64,8 @@ COMMIT -A INPUT -p icmp --icmp-type echo-request -m hashlimit --hashlimit-upto 5/s --hashlimit-mode srcip --hashlimit-srcmask 32 --hashlimit-name icmp-echo-drop -j ACCEPT # Accept IPSEC/WireGuard traffic to ports {{ subnets|join(',') }} -A INPUT -p udp -m multiport --dports {{ ports|join(',') }} -j ACCEPT -# Allow new traffic to port 22 (SSH) --A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT +# Allow new traffic to port {{ ansible_ssh_port }} (SSH) +-A INPUT -p tcp --dport {{ ansible_ssh_port }} -m conntrack --ctstate NEW -j ACCEPT {% if ipsec_enabled %} # Allow any traffic from the IPsec VPN diff --git a/roles/common/templates/rules.v6.j2 b/roles/common/templates/rules.v6.j2 index 5969a951..47226b7d 100644 --- a/roles/common/templates/rules.v6.j2 +++ b/roles/common/templates/rules.v6.j2 @@ -70,8 +70,8 @@ COMMIT -A INPUT -p icmpv6 --icmpv6-type echo-request -m hashlimit --hashlimit-upto 5/s --hashlimit-mode srcip --hashlimit-srcmask 32 --hashlimit-name icmp-echo-drop -j ACCEPT # Accept IPSEC/WireGuard traffic to ports {{ subnets|join(',') }} -A INPUT -p udp -m multiport --dports {{ ports|join(',') }} -j ACCEPT -# Allow new traffic to port 22 (SSH) --A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT +# Allow new traffic to port {{ ansible_ssh_port }} (SSH) +-A INPUT -p tcp --dport {{ ansible_ssh_port }} -m conntrack --ctstate NEW -j ACCEPT # Accept properly formatted Neighbor Discovery Protocol packets -A INPUT -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT diff --git a/server.yml b/server.yml index b46b6503..12d61751 100644 --- a/server.yml +++ b/server.yml @@ -7,6 +7,37 @@ - config.cfg tasks: - block: + - name: Wait until the cloud-init completed + wait_for: + path: /var/lib/cloud/data/result.json + delay: 10 + timeout: 600 + state: present + become: false + when: cloudinit + + - block: + - name: Ensure the config directory exists + file: + dest: "configs/{{ IP_subject_alt_name }}" + state: directory + mode: "0700" + + - name: Dump the ssh config + copy: + dest: "configs/{{ IP_subject_alt_name }}/ssh_config" + mode: "0600" + content: | + Host {{ IP_subject_alt_name }} algo + HostName {{ IP_subject_alt_name }} + User {{ ansible_ssh_user }} + Port {{ ansible_ssh_port }} + IdentityFile {{ SSH_keys.private }} + KeepAlive yes + ServerAliveInterval 30 + become: false + delegate_to: localhost + - import_role: name: common tags: common @@ -40,6 +71,7 @@ content: | server: {{ 'localhost' if inventory_hostname == 'localhost' else inventory_hostname }} server_user: {{ ansible_ssh_user }} + ansible_ssh_port: "{{ ansible_ssh_port|default(22) }}" {% if algo_provider != "local" %} ansible_ssh_private_key_file: {{ SSH_keys.private }} {% endif %} diff --git a/tests/ssh-tunnel.sh b/tests/ssh-tunnel.sh index 39f6ecc0..fba80394 100755 --- a/tests/ssh-tunnel.sh +++ b/tests/ssh-tunnel.sh @@ -6,7 +6,7 @@ PASS=$(grep ^p12_password: configs/10.0.8.100/.config.yml | awk '{print $2}') ssh-keygen -p -P ${PASS} -N '' -f configs/10.0.8.100/ssh-tunnel/desktop.pem -ssh -o StrictHostKeyChecking=no -D 127.0.0.1:1080 -f -q -C -N desktop@10.0.8.100 -i configs/10.0.8.100/ssh-tunnel/desktop.pem +ssh -o StrictHostKeyChecking=no -D 127.0.0.1:1080 -f -q -C -N desktop@10.0.8.100 -i configs/10.0.8.100/ssh-tunnel/desktop.pem -F configs/10.0.8.100/ssh_config git config --global http.proxy 'socks5://127.0.0.1:1080'