mirror of https://github.com/trailofbits/algo
Large refactor to support Ansible 2.5 (#976)
* Refactoring, booleans declaration and update users fix * Make server_name more FQDN compatible * Rename variables * Define the default value for store_cakey * Skip a prompt about the SSH user if deploying to localhost * Disable reboot for non-cloud deployments * Enable EC2 volume encryption by default * Add default server value (localhost) for the local installation Delete empty files * Add default region to aws_region_facts * Update docs * EC2 credentials fix * Warnings fix * Update deploy-from-ansible.md * Fix a typo * Remove lightsail from the docs * Disable EC2 encryption by default * rename droplet to server * Disable dependencies * Disable tls_cipher_suite * Convert wifi-exclude to a string. Update-users fix * SSH access congrats fix * 16.04 > 18.04 * Dont ask for the credentials if specified in the environment vars * GCE server name fixpull/1071/head
parent
a57a0adf5e
commit
e8947f318b
@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
- name: Provision the server
|
||||||
|
hosts: localhost
|
||||||
|
tags: algo
|
||||||
|
vars_files:
|
||||||
|
- config.cfg
|
||||||
|
|
||||||
|
pre_tasks:
|
||||||
|
- block:
|
||||||
|
- name: Local pre-tasks
|
||||||
|
import_tasks: playbooks/cloud-pre.yml
|
||||||
|
tags: always
|
||||||
|
rescue:
|
||||||
|
- debug: var=fail_hint
|
||||||
|
tags: always
|
||||||
|
- fail:
|
||||||
|
tags: always
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- role: cloud-digitalocean
|
||||||
|
when: algo_provider == "digitalocean"
|
||||||
|
- role: cloud-ec2
|
||||||
|
when: algo_provider == "ec2"
|
||||||
|
- role: cloud-vultr
|
||||||
|
when: algo_provider == "vultr"
|
||||||
|
- role: cloud-gce
|
||||||
|
when: algo_provider == "gce"
|
||||||
|
- role: cloud-azure
|
||||||
|
when: algo_provider == "azure"
|
||||||
|
- role: cloud-lightsail
|
||||||
|
when: algo_provider == "lightsail"
|
||||||
|
- role: cloud-scaleway
|
||||||
|
when: algo_provider == "scaleway"
|
||||||
|
- role: cloud-openstack
|
||||||
|
when: algo_provider == "openstack"
|
||||||
|
- role: local
|
||||||
|
when: algo_provider == "local"
|
||||||
|
|
||||||
|
post_tasks:
|
||||||
|
- block:
|
||||||
|
- name: Local post-tasks
|
||||||
|
import_tasks: playbooks/cloud-post.yml
|
||||||
|
become: false
|
||||||
|
tags: cloud
|
||||||
|
rescue:
|
||||||
|
- debug: var=fail_hint
|
||||||
|
tags: always
|
||||||
|
- fail:
|
||||||
|
tags: always
|
@ -1,98 +0,0 @@
|
|||||||
- name: Configure the server
|
|
||||||
hosts: localhost
|
|
||||||
tags: algo
|
|
||||||
vars_files:
|
|
||||||
- config.cfg
|
|
||||||
|
|
||||||
pre_tasks:
|
|
||||||
- block:
|
|
||||||
- name: Local pre-tasks
|
|
||||||
include_tasks: playbooks/local.yml
|
|
||||||
tags: [ 'always' ]
|
|
||||||
|
|
||||||
- name: Local pre-tasks
|
|
||||||
include_tasks: playbooks/local_ssh.yml
|
|
||||||
become: false
|
|
||||||
when: Deployed_By_Algo is defined and Deployed_By_Algo == "Y"
|
|
||||||
tags: [ 'local' ]
|
|
||||||
rescue:
|
|
||||||
- debug: var=fail_hint
|
|
||||||
tags: always
|
|
||||||
- fail:
|
|
||||||
tags: always
|
|
||||||
|
|
||||||
roles:
|
|
||||||
- { role: cloud-digitalocean, tags: ['digitalocean'] }
|
|
||||||
- { role: cloud-ec2, tags: ['ec2'] }
|
|
||||||
- { role: cloud-gce, tags: ['gce'] }
|
|
||||||
- { role: cloud-azure, tags: ['azure'] }
|
|
||||||
- { role: cloud-scaleway, tags: ['scaleway'] }
|
|
||||||
- { role: cloud-openstack, tags: ['openstack'] }
|
|
||||||
- { role: local, tags: ['local'] }
|
|
||||||
|
|
||||||
post_tasks:
|
|
||||||
- block:
|
|
||||||
- name: Local post-tasks
|
|
||||||
include_tasks: playbooks/post.yml
|
|
||||||
become: false
|
|
||||||
tags: [ 'cloud' ]
|
|
||||||
rescue:
|
|
||||||
- debug: var=fail_hint
|
|
||||||
tags: always
|
|
||||||
- fail:
|
|
||||||
tags: always
|
|
||||||
|
|
||||||
- name: Configure the server and install required software
|
|
||||||
hosts: vpn-host
|
|
||||||
gather_facts: false
|
|
||||||
tags: algo
|
|
||||||
become: true
|
|
||||||
vars_files:
|
|
||||||
- config.cfg
|
|
||||||
|
|
||||||
pre_tasks:
|
|
||||||
- block:
|
|
||||||
- name: Common pre-tasks
|
|
||||||
include_tasks: playbooks/common.yml
|
|
||||||
tags: [ 'digitalocean', 'ec2', 'gce', 'azure', 'lightsail', 'scaleway', 'openstack', 'local', 'pre' ]
|
|
||||||
rescue:
|
|
||||||
- debug: var=fail_hint
|
|
||||||
tags: always
|
|
||||||
- fail:
|
|
||||||
tags: always
|
|
||||||
|
|
||||||
roles:
|
|
||||||
- { role: dns_adblocking, tags: [ 'dns', 'adblock' ] }
|
|
||||||
- { role: ssh_tunneling, tags: [ 'ssh_tunneling' ] }
|
|
||||||
- { role: wireguard, tags: [ 'vpn', 'wireguard' ], when: wireguard_enabled }
|
|
||||||
- { role: vpn, tags: [ 'vpn' ] }
|
|
||||||
|
|
||||||
post_tasks:
|
|
||||||
- block:
|
|
||||||
- debug:
|
|
||||||
msg:
|
|
||||||
- "{{ congrats.common.split('\n') }}"
|
|
||||||
- " {{ congrats.p12_pass }}"
|
|
||||||
- " {% if Store_CAKEY is defined and Store_CAKEY == 'N' %}{% else %}{{ congrats.ca_key_pass }}{% endif %}"
|
|
||||||
- " {% if cloud_deployment is defined %}{{ congrats.ssh_access }}{% endif %}"
|
|
||||||
tags: always
|
|
||||||
|
|
||||||
- name: Save the CA key password
|
|
||||||
local_action: >
|
|
||||||
shell echo "{{ easyrsa_CA_password }}" > /tmp/ca_password
|
|
||||||
become: no
|
|
||||||
tags: tests
|
|
||||||
|
|
||||||
- name: Delete the CA key
|
|
||||||
local_action:
|
|
||||||
module: file
|
|
||||||
path: "configs/{{ IP_subject_alt_name }}/pki/private/cakey.pem"
|
|
||||||
state: absent
|
|
||||||
become: no
|
|
||||||
tags: always
|
|
||||||
when: Store_CAKEY is defined and Store_CAKEY == "N"
|
|
||||||
rescue:
|
|
||||||
- debug: var=fail_hint
|
|
||||||
tags: always
|
|
||||||
- fail:
|
|
||||||
tags: always
|
|
@ -0,0 +1,8 @@
|
|||||||
|
### Configuration file
|
||||||
|
|
||||||
|
You need to create a configuration file in INI format with your api key (https://my.vultr.com/settings/#settingsapi)
|
||||||
|
|
||||||
|
```
|
||||||
|
[default]
|
||||||
|
key = <your api key>
|
||||||
|
```
|
@ -0,0 +1,137 @@
|
|||||||
|
---
|
||||||
|
- name: Ask user for the input
|
||||||
|
hosts: localhost
|
||||||
|
tags: algo
|
||||||
|
vars:
|
||||||
|
defaults:
|
||||||
|
server_name: algo
|
||||||
|
ondemand_cellular: false
|
||||||
|
ondemand_wifi: false
|
||||||
|
local_dns: false
|
||||||
|
ssh_tunneling: false
|
||||||
|
windows: false
|
||||||
|
store_cakey: false
|
||||||
|
providers_map:
|
||||||
|
- { name: DigitalOcean, alias: digitalocean }
|
||||||
|
- { name: Amazon EC2, alias: ec2 }
|
||||||
|
- { name: Vultr, alias: vultr }
|
||||||
|
- { name: Microsoft Azure, alias: azure }
|
||||||
|
- { name: Google Compute Engine, alias: gce }
|
||||||
|
- { name: Scaleway, alias: scaleway}
|
||||||
|
- { name: OpenStack (DreamCompute optimised), alias: openstack }
|
||||||
|
- { name: Install to existing Ubuntu 18.04 server (Advanced), alias: local }
|
||||||
|
vars_files:
|
||||||
|
- config.cfg
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
What provider would you like to use?
|
||||||
|
{% for p in providers_map %}
|
||||||
|
{{ loop.index }}. {{ p['name']}}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Enter the number of your desired provider
|
||||||
|
register: _algo_provider
|
||||||
|
when: provider is undefined
|
||||||
|
|
||||||
|
- name: Set facts based on the input
|
||||||
|
set_fact:
|
||||||
|
algo_provider: "{{ provider | default(providers_map[_algo_provider.user_input|default(omit)|int - 1]['alias']) }}"
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Name the vpn server
|
||||||
|
[algo]
|
||||||
|
register: _algo_server_name
|
||||||
|
when:
|
||||||
|
- server_name is undefined
|
||||||
|
- algo_provider != "local"
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Do you want macOS/iOS clients to enable "VPN On Demand" when connected to cellular networks?
|
||||||
|
[y/N]
|
||||||
|
register: _ondemand_cellular
|
||||||
|
when: ondemand_cellular is undefined
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Do you want macOS/iOS clients to enable "VPN On Demand" when connected to Wi-Fi?
|
||||||
|
[y/N]
|
||||||
|
register: _ondemand_wifi
|
||||||
|
when: ondemand_wifi is undefined
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
List the names of trusted Wi-Fi networks (if any) that macOS/iOS clients exclude from using the VPN
|
||||||
|
(e.g., your home network. Comma-separated value, e.g., HomeNet,OfficeWifi,AlgoWiFi)
|
||||||
|
register: _ondemand_wifi_exclude
|
||||||
|
when:
|
||||||
|
- ondemand_wifi_exclude is undefined
|
||||||
|
- (ondemand_wifi|default(false)|bool) or
|
||||||
|
(booleans_map[_ondemand_wifi.user_input|default(omit)]|default(false))
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Do you want to install a DNS resolver on this VPN server, to block ads while surfing?
|
||||||
|
[y/N]
|
||||||
|
register: _local_dns
|
||||||
|
when: local_dns is undefined
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Do you want each user to have their own account for SSH tunneling?
|
||||||
|
[y/N]
|
||||||
|
register: _ssh_tunneling
|
||||||
|
when: ssh_tunneling is undefined
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Do you want the VPN to support Windows 10 or Linux Desktop clients? (enables compatible ciphers and key exchange, less secure)
|
||||||
|
[y/N]
|
||||||
|
register: _windows
|
||||||
|
when: windows is undefined
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Do you want to retain the CA key? (required to add users in the future, but less secure)
|
||||||
|
[y/N]
|
||||||
|
register: _store_cakey
|
||||||
|
when: store_cakey is undefined
|
||||||
|
|
||||||
|
- name: Set facts based on the input
|
||||||
|
set_fact:
|
||||||
|
algo_server_name: >-
|
||||||
|
{% if server_name is defined %}{% set _server = server_name %}
|
||||||
|
{%- elif _algo_server_name.user_input is defined and _algo_server_name.user_input != "" %}{% set _server = _algo_server_name.user_input %}
|
||||||
|
{%- else %}{% set _server = defaults['server_name'] %}{% endif -%}
|
||||||
|
{{ _server | regex_replace('(?!\.)(\W|_)', '-') }}
|
||||||
|
algo_ondemand_cellular: >-
|
||||||
|
{% if ondemand_cellular is defined %}{{ ondemand_cellular | bool }}
|
||||||
|
{%- elif _ondemand_cellular.user_input is defined and _ondemand_cellular.user_input != "" %}{{ booleans_map[_ondemand_cellular.user_input] | default(defaults['ondemand_cellular']) }}
|
||||||
|
{%- else %}false{% endif %}
|
||||||
|
algo_ondemand_wifi: >-
|
||||||
|
{% if ondemand_wifi is defined %}{{ ondemand_wifi | bool }}
|
||||||
|
{%- elif _ondemand_wifi.user_input is defined and _ondemand_wifi.user_input != "" %}{{ booleans_map[_ondemand_wifi.user_input] | default(defaults['ondemand_wifi']) }}
|
||||||
|
{%- else %}false{% endif %}
|
||||||
|
algo_ondemand_wifi_exclude: >-
|
||||||
|
{% if ondemand_wifi_exclude is defined %}{{ ondemand_wifi_exclude }}
|
||||||
|
{%- elif _ondemand_wifi_exclude.user_input is defined and _ondemand_wifi_exclude.user_input != "" %}{{ _ondemand_wifi_exclude.user_input }}
|
||||||
|
{%- else %}_null{% endif %}
|
||||||
|
algo_local_dns: >-
|
||||||
|
{% if local_dns is defined %}{{ local_dns | bool }}
|
||||||
|
{%- elif _local_dns.user_input is defined and _local_dns.user_input != "" %}{{ booleans_map[_local_dns.user_input] | default(defaults['local_dns']) }}
|
||||||
|
{%- else %}false{% endif %}
|
||||||
|
algo_ssh_tunneling: >-
|
||||||
|
{% if ssh_tunneling is defined %}{{ ssh_tunneling | bool }}
|
||||||
|
{%- elif _ssh_tunneling.user_input is defined and _ssh_tunneling.user_input != "" %}{{ booleans_map[_ssh_tunneling.user_input] | default(defaults['ssh_tunneling']) }}
|
||||||
|
{%- else %}false{% endif %}
|
||||||
|
algo_windows: >-
|
||||||
|
{% if windows is defined %}{{ windows | bool }}
|
||||||
|
{%- elif _windows.user_input is defined and _windows.user_input != "" %}{{ booleans_map[_windows.user_input] | default(defaults['windows']) }}
|
||||||
|
{%- else %}false{% endif %}
|
||||||
|
algo_store_cakey: >-
|
||||||
|
{% if store_cakey is defined %}{{ store_cakey | bool }}
|
||||||
|
{%- elif _store_cakey.user_input is defined and _store_cakey.user_input != "" %}{{ booleans_map[_store_cakey.user_input] | default(defaults['store_cakey']) }}
|
||||||
|
{%- else %}false{% endif %}
|
@ -1,217 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Copyright: Ansible Project
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: digital_ocean_tag
|
|
||||||
short_description: Create and remove tag(s) to DigitalOcean resource.
|
|
||||||
description:
|
|
||||||
- Create and remove tag(s) to DigitalOcean resource.
|
|
||||||
author: "Victor Volle (@kontrafiktion)"
|
|
||||||
version_added: "2.2"
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- The name of the tag. The supported characters for names include
|
|
||||||
alphanumeric characters, dashes, and underscores.
|
|
||||||
required: true
|
|
||||||
resource_id:
|
|
||||||
description:
|
|
||||||
- The ID of the resource to operate on.
|
|
||||||
- The data type of resource_id is changed from integer to string, from version 2.5.
|
|
||||||
aliases: ['droplet_id']
|
|
||||||
resource_type:
|
|
||||||
description:
|
|
||||||
- The type of resource to operate on. Currently, only tagging of
|
|
||||||
droplets is supported.
|
|
||||||
default: droplet
|
|
||||||
choices: ['droplet']
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Whether the tag should be present or absent on the resource.
|
|
||||||
default: present
|
|
||||||
choices: ['present', 'absent']
|
|
||||||
api_token:
|
|
||||||
description:
|
|
||||||
- DigitalOcean api token.
|
|
||||||
|
|
||||||
notes:
|
|
||||||
- Two environment variables can be used, DO_API_KEY and DO_API_TOKEN.
|
|
||||||
They both refer to the v2 token.
|
|
||||||
- As of Ansible 2.0, Version 2 of the DigitalOcean API is used.
|
|
||||||
|
|
||||||
requirements:
|
|
||||||
- "python >= 2.6"
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
- name: create a tag
|
|
||||||
digital_ocean_tag:
|
|
||||||
name: production
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: tag a resource; creating the tag if it does not exists
|
|
||||||
digital_ocean_tag:
|
|
||||||
name: "{{ item }}"
|
|
||||||
resource_id: "73333005"
|
|
||||||
state: present
|
|
||||||
with_items:
|
|
||||||
- staging
|
|
||||||
- dbserver
|
|
||||||
|
|
||||||
- name: untag a resource
|
|
||||||
digital_ocean_tag:
|
|
||||||
name: staging
|
|
||||||
resource_id: "73333005"
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
# Deleting a tag also untags all the resources that have previously been
|
|
||||||
# tagged with it
|
|
||||||
- name: remove a tag
|
|
||||||
digital_ocean_tag:
|
|
||||||
name: dbserver
|
|
||||||
state: absent
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
data:
|
|
||||||
description: a DigitalOcean Tag resource
|
|
||||||
returned: success and no resource constraint
|
|
||||||
type: dict
|
|
||||||
sample: {
|
|
||||||
"tag": {
|
|
||||||
"name": "awesome",
|
|
||||||
"resources": {
|
|
||||||
"droplets": {
|
|
||||||
"count": 0,
|
|
||||||
"last_tagged": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
|
|
||||||
from traceback import format_exc
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible.module_utils.digital_ocean import DigitalOceanHelper
|
|
||||||
from ansible.module_utils._text import to_native
|
|
||||||
|
|
||||||
|
|
||||||
def core(module):
|
|
||||||
state = module.params['state']
|
|
||||||
name = module.params['name']
|
|
||||||
resource_id = module.params['resource_id']
|
|
||||||
resource_type = module.params['resource_type']
|
|
||||||
|
|
||||||
rest = DigitalOceanHelper(module)
|
|
||||||
|
|
||||||
# Check if api_token is valid or not
|
|
||||||
response = rest.get('account')
|
|
||||||
if response.status_code == 401:
|
|
||||||
module.fail_json(msg='Failed to login using api_token, please verify '
|
|
||||||
'validity of api_token')
|
|
||||||
if state == 'present':
|
|
||||||
response = rest.get('tags/{0}'.format(name))
|
|
||||||
status_code = response.status_code
|
|
||||||
resp_json = response.json
|
|
||||||
changed = False
|
|
||||||
if status_code == 200 and resp_json['tag']['name'] == name:
|
|
||||||
changed = False
|
|
||||||
else:
|
|
||||||
# Ensure Tag exists
|
|
||||||
response = rest.post("tags", data={'name': name})
|
|
||||||
status_code = response.status_code
|
|
||||||
resp_json = response.json
|
|
||||||
if status_code == 201:
|
|
||||||
changed = True
|
|
||||||
elif status_code == 422:
|
|
||||||
changed = False
|
|
||||||
else:
|
|
||||||
module.exit_json(changed=False, data=resp_json)
|
|
||||||
|
|
||||||
if resource_id is None:
|
|
||||||
# No resource defined, we're done.
|
|
||||||
module.exit_json(changed=changed, data=resp_json)
|
|
||||||
else:
|
|
||||||
# Check if resource is already tagged or not
|
|
||||||
found = False
|
|
||||||
url = "{0}?tag_name={1}".format(resource_type, name)
|
|
||||||
if resource_type == 'droplet':
|
|
||||||
url = "droplets?tag_name={0}".format(name)
|
|
||||||
response = rest.get(url)
|
|
||||||
status_code = response.status_code
|
|
||||||
resp_json = response.json
|
|
||||||
if status_code == 200:
|
|
||||||
for resource in resp_json['droplets']:
|
|
||||||
if not found and resource['id'] == int(resource_id):
|
|
||||||
found = True
|
|
||||||
break
|
|
||||||
if not found:
|
|
||||||
# If resource is not tagged, tag a resource
|
|
||||||
url = "tags/{0}/resources".format(name)
|
|
||||||
payload = {
|
|
||||||
'resources': [{
|
|
||||||
'resource_id': resource_id,
|
|
||||||
'resource_type': resource_type}]}
|
|
||||||
response = rest.post(url, data=payload)
|
|
||||||
if response.status_code == 204:
|
|
||||||
module.exit_json(changed=True)
|
|
||||||
else:
|
|
||||||
module.fail_json(msg="error tagging resource '{0}': {1}".format(resource_id, response.json["message"]))
|
|
||||||
else:
|
|
||||||
# Already tagged resource
|
|
||||||
module.exit_json(changed=False)
|
|
||||||
else:
|
|
||||||
# Unable to find resource specified by user
|
|
||||||
module.fail_json(msg=resp_json['message'])
|
|
||||||
|
|
||||||
elif state == 'absent':
|
|
||||||
if resource_id:
|
|
||||||
url = "tags/{0}/resources".format(name)
|
|
||||||
payload = {
|
|
||||||
'resources': [{
|
|
||||||
'resource_id': resource_id,
|
|
||||||
'resource_type': resource_type}]}
|
|
||||||
response = rest.delete(url, data=payload)
|
|
||||||
else:
|
|
||||||
url = "tags/{0}".format(name)
|
|
||||||
response = rest.delete(url)
|
|
||||||
if response.status_code == 204:
|
|
||||||
module.exit_json(changed=True)
|
|
||||||
else:
|
|
||||||
module.exit_json(changed=False, data=response.json)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
module = AnsibleModule(
|
|
||||||
argument_spec=dict(
|
|
||||||
name=dict(type='str', required=True),
|
|
||||||
resource_id=dict(aliases=['droplet_id'], type='str'),
|
|
||||||
resource_type=dict(choices=['droplet'], default='droplet'),
|
|
||||||
state=dict(choices=['present', 'absent'], default='present'),
|
|
||||||
api_token=dict(aliases=['API_TOKEN'], no_log=True),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
core(module)
|
|
||||||
except Exception as e:
|
|
||||||
module.fail_json(msg=to_native(e), exception=format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
@ -1,216 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# This file is part of Ansible
|
|
||||||
#
|
|
||||||
# Ansible is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Ansible is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'status': ['preview'],
|
|
||||||
'supported_by': 'community',
|
|
||||||
'version': '1.1'}
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: ec2_ami_copy
|
|
||||||
short_description: copies AMI between AWS regions, return new image id
|
|
||||||
description:
|
|
||||||
- Copies AMI from a source region to a destination region. This module has a dependency on python-boto >= 2.5
|
|
||||||
version_added: "2.0"
|
|
||||||
options:
|
|
||||||
source_region:
|
|
||||||
description:
|
|
||||||
- the source region that AMI should be copied from
|
|
||||||
required: true
|
|
||||||
source_image_id:
|
|
||||||
description:
|
|
||||||
- the id of the image in source region that should be copied
|
|
||||||
required: true
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- The name of the new image to copy
|
|
||||||
required: true
|
|
||||||
default: null
|
|
||||||
description:
|
|
||||||
description:
|
|
||||||
- An optional human-readable string describing the contents and purpose of the new AMI.
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
encrypted:
|
|
||||||
description:
|
|
||||||
- Whether or not to encrypt the target image
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
version_added: "2.2"
|
|
||||||
kms_key_id:
|
|
||||||
description:
|
|
||||||
- KMS key id used to encrypt image. If not specified, uses default EBS Customer Master Key (CMK) for your account.
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
version_added: "2.2"
|
|
||||||
wait:
|
|
||||||
description:
|
|
||||||
- wait for the copied AMI to be in state 'available' before returning.
|
|
||||||
required: false
|
|
||||||
default: false
|
|
||||||
tags:
|
|
||||||
description:
|
|
||||||
- a hash/dictionary of tags to add to the new copied AMI; '{"key":"value"}' and '{"key":"value","key":"value"}'
|
|
||||||
required: false
|
|
||||||
default: null
|
|
||||||
|
|
||||||
author: Amir Moulavi <amir.moulavi@gmail.com>, Tim C <defunct@defunct.io>
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- aws
|
|
||||||
- ec2
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Basic AMI Copy
|
|
||||||
- ec2_ami_copy:
|
|
||||||
source_region: us-east-1
|
|
||||||
region: eu-west-1
|
|
||||||
source_image_id: ami-xxxxxxx
|
|
||||||
|
|
||||||
# AMI copy wait until available
|
|
||||||
- ec2_ami_copy:
|
|
||||||
source_region: us-east-1
|
|
||||||
region: eu-west-1
|
|
||||||
source_image_id: ami-xxxxxxx
|
|
||||||
wait: yes
|
|
||||||
register: image_id
|
|
||||||
|
|
||||||
# Named AMI copy
|
|
||||||
- ec2_ami_copy:
|
|
||||||
source_region: us-east-1
|
|
||||||
region: eu-west-1
|
|
||||||
source_image_id: ami-xxxxxxx
|
|
||||||
name: My-Awesome-AMI
|
|
||||||
description: latest patch
|
|
||||||
|
|
||||||
# Tagged AMI copy
|
|
||||||
- ec2_ami_copy:
|
|
||||||
source_region: us-east-1
|
|
||||||
region: eu-west-1
|
|
||||||
source_image_id: ami-xxxxxxx
|
|
||||||
tags:
|
|
||||||
Name: My-Super-AMI
|
|
||||||
Patch: 1.2.3
|
|
||||||
|
|
||||||
# Encrypted AMI copy
|
|
||||||
- ec2_ami_copy:
|
|
||||||
source_region: us-east-1
|
|
||||||
region: eu-west-1
|
|
||||||
source_image_id: ami-xxxxxxx
|
|
||||||
encrypted: yes
|
|
||||||
|
|
||||||
# Encrypted AMI copy with specified key
|
|
||||||
- ec2_ami_copy:
|
|
||||||
source_region: us-east-1
|
|
||||||
region: eu-west-1
|
|
||||||
source_image_id: ami-xxxxxxx
|
|
||||||
encrypted: yes
|
|
||||||
kms_key_id: arn:aws:kms:us-east-1:XXXXXXXXXXXX:key/746de6ea-50a4-4bcb-8fbc-e3b29f2d367b
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible.module_utils.ec2 import (boto3_conn, ec2_argument_spec, get_aws_connection_info)
|
|
||||||
|
|
||||||
try:
|
|
||||||
import boto
|
|
||||||
import boto.ec2
|
|
||||||
HAS_BOTO = True
|
|
||||||
except ImportError:
|
|
||||||
HAS_BOTO = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
import boto3
|
|
||||||
from botocore.exceptions import ClientError, NoCredentialsError, NoRegionError
|
|
||||||
HAS_BOTO3 = True
|
|
||||||
except ImportError:
|
|
||||||
HAS_BOTO3 = False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def copy_image(ec2, module):
|
|
||||||
"""
|
|
||||||
Copies an AMI
|
|
||||||
|
|
||||||
module : AnsibleModule object
|
|
||||||
ec2: ec2 connection object
|
|
||||||
"""
|
|
||||||
|
|
||||||
tags = module.params.get('tags')
|
|
||||||
|
|
||||||
params = {'SourceRegion': module.params.get('source_region'),
|
|
||||||
'SourceImageId': module.params.get('source_image_id'),
|
|
||||||
'Name': module.params.get('name'),
|
|
||||||
'Description': module.params.get('description'),
|
|
||||||
'Encrypted': module.params.get('encrypted'),
|
|
||||||
# 'KmsKeyId': module.params.get('kms_key_id')
|
|
||||||
}
|
|
||||||
if module.params.get('kms_key_id'):
|
|
||||||
params['KmsKeyId'] = module.params.get('kms_key_id')
|
|
||||||
|
|
||||||
try:
|
|
||||||
image_id = ec2.copy_image(**params)['ImageId']
|
|
||||||
if module.params.get('wait'):
|
|
||||||
ec2.get_waiter('image_available').wait(ImageIds=[image_id])
|
|
||||||
if module.params.get('tags'):
|
|
||||||
ec2.create_tags(
|
|
||||||
Resources=[image_id],
|
|
||||||
Tags=[{'Key' : k, 'Value': v} for k,v in module.params.get('tags').items()]
|
|
||||||
)
|
|
||||||
|
|
||||||
module.exit_json(changed=True, image_id=image_id)
|
|
||||||
except ClientError as ce:
|
|
||||||
module.fail_json(msg=ce)
|
|
||||||
except NoCredentialsError:
|
|
||||||
module.fail_json(msg="Unable to locate AWS credentials")
|
|
||||||
except Exception as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = ec2_argument_spec()
|
|
||||||
argument_spec.update(dict(
|
|
||||||
source_region=dict(required=True),
|
|
||||||
source_image_id=dict(required=True),
|
|
||||||
name=dict(required=True),
|
|
||||||
description=dict(default=''),
|
|
||||||
encrypted=dict(type='bool', required=False),
|
|
||||||
kms_key_id=dict(type='str', required=False),
|
|
||||||
wait=dict(type='bool', default=False, required=False),
|
|
||||||
tags=dict(type='dict')))
|
|
||||||
|
|
||||||
module = AnsibleModule(argument_spec=argument_spec)
|
|
||||||
|
|
||||||
if not HAS_BOTO:
|
|
||||||
module.fail_json(msg='boto required for this module')
|
|
||||||
# TODO: Check botocore version
|
|
||||||
region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
|
|
||||||
|
|
||||||
if HAS_BOTO3:
|
|
||||||
|
|
||||||
try:
|
|
||||||
ec2 = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url,
|
|
||||||
**aws_connect_params)
|
|
||||||
except NoRegionError:
|
|
||||||
module.fail_json(msg='AWS Region is required')
|
|
||||||
else:
|
|
||||||
module.fail_json(msg='boto3 required for this module')
|
|
||||||
|
|
||||||
copy_image(ec2, module)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
@ -0,0 +1,139 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright 2013 Google Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: gce_region_facts
|
||||||
|
version_added: "5.3"
|
||||||
|
short_description: Gather facts about GCE regions.
|
||||||
|
description:
|
||||||
|
- Gather facts about GCE regions.
|
||||||
|
options:
|
||||||
|
service_account_email:
|
||||||
|
version_added: "1.6"
|
||||||
|
description:
|
||||||
|
- service account email
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
aliases: []
|
||||||
|
pem_file:
|
||||||
|
version_added: "1.6"
|
||||||
|
description:
|
||||||
|
- path to the pem file associated with the service account email
|
||||||
|
This option is deprecated. Use 'credentials_file'.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
aliases: []
|
||||||
|
credentials_file:
|
||||||
|
version_added: "2.1.0"
|
||||||
|
description:
|
||||||
|
- path to the JSON file associated with the service account email
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
aliases: []
|
||||||
|
project_id:
|
||||||
|
version_added: "1.6"
|
||||||
|
description:
|
||||||
|
- your GCE project ID
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
aliases: []
|
||||||
|
requirements:
|
||||||
|
- "python >= 2.6"
|
||||||
|
- "apache-libcloud >= 0.13.3, >= 0.17.0 if using JSON credentials"
|
||||||
|
author: "Jack Ivanov (@jackivanov)"
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Gather facts about all regions
|
||||||
|
- gce_region_facts:
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
regions:
|
||||||
|
returned: on success
|
||||||
|
description: >
|
||||||
|
Each element consists of a dict with all the information related
|
||||||
|
to that region.
|
||||||
|
type: list
|
||||||
|
sample: "[{
|
||||||
|
"name": "asia-east1",
|
||||||
|
"status": "UP",
|
||||||
|
"zones": [
|
||||||
|
{
|
||||||
|
"name": "asia-east1-a",
|
||||||
|
"status": "UP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "asia-east1-b",
|
||||||
|
"status": "UP"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "asia-east1-c",
|
||||||
|
"status": "UP"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]"
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
from libcloud.compute.types import Provider
|
||||||
|
from libcloud.compute.providers import get_driver
|
||||||
|
from libcloud.common.google import GoogleBaseError, QuotaExceededError, ResourceExistsError, ResourceNotFoundError
|
||||||
|
_ = Provider.GCE
|
||||||
|
HAS_LIBCLOUD = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_LIBCLOUD = False
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.gce import gce_connect, unexpected_error_msg
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
service_account_email=dict(),
|
||||||
|
pem_file=dict(type='path'),
|
||||||
|
credentials_file=dict(type='path'),
|
||||||
|
project_id=dict(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if not HAS_LIBCLOUD:
|
||||||
|
module.fail_json(msg='libcloud with GCE support (0.17.0+) required for this module')
|
||||||
|
|
||||||
|
gce = gce_connect(module)
|
||||||
|
|
||||||
|
changed = False
|
||||||
|
gce_regions = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
regions = gce.ex_list_regions()
|
||||||
|
for r in regions:
|
||||||
|
gce_region = {}
|
||||||
|
gce_region['name'] = r.name
|
||||||
|
gce_region['status'] = r.status
|
||||||
|
gce_region['zones'] = []
|
||||||
|
for z in r.zones:
|
||||||
|
gce_zone = {}
|
||||||
|
gce_zone['name'] = z.name
|
||||||
|
gce_zone['status'] = z.status
|
||||||
|
gce_region['zones'].append(gce_zone)
|
||||||
|
gce_regions.append(gce_region)
|
||||||
|
json_output = { 'regions': gce_regions }
|
||||||
|
module.exit_json(changed=False, results=json_output)
|
||||||
|
except ResourceNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: lightsail_region_facts
|
||||||
|
short_description: Gather facts about AWS Lightsail regions.
|
||||||
|
description:
|
||||||
|
- Gather facts about AWS Lightsail regions.
|
||||||
|
version_added: "2.5.3"
|
||||||
|
author: "Jack Ivanov (@jackivanov)"
|
||||||
|
options:
|
||||||
|
requirements:
|
||||||
|
- "python >= 2.6"
|
||||||
|
- boto3
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- aws
|
||||||
|
- ec2
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Gather facts about all regions
|
||||||
|
- lightsail_region_facts:
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
regions:
|
||||||
|
returned: on success
|
||||||
|
description: >
|
||||||
|
Each element consists of a dict with all the information related
|
||||||
|
to that region.
|
||||||
|
type: list
|
||||||
|
sample: "[{
|
||||||
|
"availabilityZones": [],
|
||||||
|
"continentCode": "NA",
|
||||||
|
"description": "This region is recommended to serve users in the eastern United States",
|
||||||
|
"displayName": "Virginia",
|
||||||
|
"name": "us-east-1"
|
||||||
|
}]"
|
||||||
|
'''
|
||||||
|
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
try:
|
||||||
|
import botocore
|
||||||
|
HAS_BOTOCORE = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_BOTOCORE = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
import boto3
|
||||||
|
except ImportError:
|
||||||
|
# will be caught by imported HAS_BOTO3
|
||||||
|
pass
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.ec2 import (ec2_argument_spec, get_aws_connection_info, boto3_conn,
|
||||||
|
HAS_BOTO3, camel_dict_to_snake_dict)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = ec2_argument_spec()
|
||||||
|
module = AnsibleModule(argument_spec=argument_spec)
|
||||||
|
|
||||||
|
if not HAS_BOTO3:
|
||||||
|
module.fail_json(msg='Python module "boto3" is missing, please install it')
|
||||||
|
|
||||||
|
if not HAS_BOTOCORE:
|
||||||
|
module.fail_json(msg='Python module "botocore" is missing, please install it')
|
||||||
|
|
||||||
|
try:
|
||||||
|
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
|
||||||
|
|
||||||
|
client = None
|
||||||
|
try:
|
||||||
|
client = boto3_conn(module, conn_type='client', resource='lightsail',
|
||||||
|
region=region, endpoint=ec2_url, **aws_connect_kwargs)
|
||||||
|
except (botocore.exceptions.ClientError, botocore.exceptions.ValidationError) as e:
|
||||||
|
module.fail_json(msg='Failed while connecting to the lightsail service: %s' % e, exception=traceback.format_exc())
|
||||||
|
|
||||||
|
response = client.get_regions(
|
||||||
|
includeAvailabilityZones=False
|
||||||
|
)
|
||||||
|
module.exit_json(changed=False, results=response)
|
||||||
|
except (botocore.exceptions.ClientError, Exception) as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
- name: Include prompts playbook
|
||||||
|
import_playbook: input.yml
|
||||||
|
|
||||||
|
- name: Include cloud provisioning playbook
|
||||||
|
import_playbook: cloud.yml
|
||||||
|
|
||||||
|
- name: Include server configuration playbook
|
||||||
|
import_playbook: server.yml
|
@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
- name: Set subjectAltName as afact
|
||||||
|
set_fact:
|
||||||
|
IP_subject_alt_name: "{% if algo_provider == 'local' %}{{ IP_subject_alt_name }}{% else %}{{ cloud_instance_ip }}{% endif %}"
|
||||||
|
|
||||||
|
- name: Add the server to an inventory group
|
||||||
|
add_host:
|
||||||
|
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_python_interpreter: "/usr/bin/python2.7"
|
||||||
|
algo_provider: "{{ algo_provider }}"
|
||||||
|
algo_server_name: "{{ algo_server_name }}"
|
||||||
|
algo_ondemand_cellular: "{{ algo_ondemand_cellular }}"
|
||||||
|
algo_ondemand_wifi: "{{ algo_ondemand_wifi }}"
|
||||||
|
algo_ondemand_wifi_exclude: "{{ algo_ondemand_wifi_exclude }}"
|
||||||
|
algo_local_dns: "{{ algo_local_dns }}"
|
||||||
|
algo_ssh_tunneling: "{{ algo_ssh_tunneling }}"
|
||||||
|
algo_windows: "{{ algo_windows }}"
|
||||||
|
algo_store_cakey: "{{ algo_store_cakey }}"
|
||||||
|
IP_subject_alt_name: "{{ IP_subject_alt_name }}"
|
||||||
|
|
||||||
|
- name: Additional variables for the server
|
||||||
|
add_host:
|
||||||
|
name: "{% if cloud_instance_ip == 'localhost' %}localhost{% else %}{{ cloud_instance_ip }}{% endif %}"
|
||||||
|
ansible_ssh_private_key_file: "{{ SSH_keys.private }}"
|
||||||
|
when: algo_provider != 'local'
|
||||||
|
|
||||||
|
- name: Wait until SSH becomes ready...
|
||||||
|
wait_for:
|
||||||
|
port: 22
|
||||||
|
host: "{{ cloud_instance_ip }}"
|
||||||
|
search_regex: "OpenSSH"
|
||||||
|
delay: 10
|
||||||
|
timeout: 320
|
||||||
|
state: present
|
||||||
|
when: cloud_instance_ip != "localhost"
|
||||||
|
|
||||||
|
- debug:
|
||||||
|
var: IP_subject_alt_name
|
||||||
|
|
||||||
|
- name: A short pause, in order to be sure the instance is ready
|
||||||
|
pause:
|
||||||
|
seconds: 20
|
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
- name: Generate the SSH private key
|
||||||
|
openssl_privatekey:
|
||||||
|
path: "{{ SSH_keys.private }}"
|
||||||
|
size: 2048
|
||||||
|
mode: "0600"
|
||||||
|
type: RSA
|
||||||
|
|
||||||
|
- name: Generate the SSH public key
|
||||||
|
openssl_publickey:
|
||||||
|
path: "{{ SSH_keys.public }}"
|
||||||
|
privatekey_path: "{{ SSH_keys.private }}"
|
||||||
|
format: OpenSSH
|
@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- name: Check the system
|
|
||||||
raw: uname -a
|
|
||||||
register: OS
|
|
||||||
|
|
||||||
- name: Ubuntu pre-tasks
|
|
||||||
include_tasks: ubuntu.yml
|
|
||||||
when: '"Ubuntu" in OS.stdout or "Linux" in OS.stdout'
|
|
||||||
|
|
||||||
- name: FreeBSD pre-tasks
|
|
||||||
include_tasks: freebsd.yml
|
|
||||||
when: '"FreeBSD" in OS.stdout'
|
|
||||||
|
|
||||||
- include_tasks: facts/main.yml
|
|
@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- set_fact:
|
|
||||||
config_prefix: "/usr/local/"
|
|
||||||
root_group: wheel
|
|
||||||
ssh_service_name: sshd
|
|
||||||
apparmor_enabled: false
|
|
||||||
strongswan_additional_plugins:
|
|
||||||
- kernel-pfroute
|
|
||||||
- kernel-pfkey
|
|
@ -1,44 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- name: Gather Facts
|
|
||||||
setup:
|
|
||||||
|
|
||||||
- name: Ensure the algo ssh key exist on the server
|
|
||||||
authorized_key:
|
|
||||||
user: "{{ ansible_ssh_user }}"
|
|
||||||
state: present
|
|
||||||
key: "{{ lookup('file', '{{ SSH_keys.public }}') }}"
|
|
||||||
tags: [ 'cloud' ]
|
|
||||||
|
|
||||||
- name: Check if IPv6 configured
|
|
||||||
set_fact:
|
|
||||||
ipv6_support: "{% if ansible_default_ipv6['gateway'] is defined %}true{% else %}false{% endif %}"
|
|
||||||
|
|
||||||
- name: Set facts if the deployment in a cloud
|
|
||||||
set_fact:
|
|
||||||
cloud_deployment: true
|
|
||||||
tags: ['cloud']
|
|
||||||
|
|
||||||
- name: Generate password for the CA key
|
|
||||||
local_action:
|
|
||||||
module: shell
|
|
||||||
openssl rand -hex 16
|
|
||||||
become: no
|
|
||||||
register: CA_password
|
|
||||||
|
|
||||||
- name: Generate p12 export password
|
|
||||||
local_action:
|
|
||||||
module: shell
|
|
||||||
openssl rand 8 | python -c 'import sys,string; chars=string.ascii_letters + string.digits + "_@"; print "".join([chars[ord(c) % 64] for c in list(sys.stdin.read())])'
|
|
||||||
become: no
|
|
||||||
register: p12_export_password_generated
|
|
||||||
when: p12_export_password is not defined
|
|
||||||
|
|
||||||
- name: Define password facts
|
|
||||||
set_fact:
|
|
||||||
easyrsa_p12_export_password: "{{ p12_export_password|default(p12_export_password_generated.stdout) }}"
|
|
||||||
easyrsa_CA_password: "{{ CA_password.stdout }}"
|
|
||||||
|
|
||||||
- name: Define the commonName
|
|
||||||
set_fact:
|
|
||||||
IP_subject_alt_name: "{{ IP_subject_alt_name }}"
|
|
@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Install prerequisites
|
|
||||||
raw: sleep 10 && env ASSUME_ALWAYS_YES=YES sudo pkg install -y python27
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Configure defaults
|
|
||||||
raw: sudo ln -sf /usr/local/bin/python2.7 /usr/bin/python2.7
|
|
||||||
|
|
||||||
- include_tasks: facts/FreeBSD.yml
|
|
@ -1,31 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- name: Generate the SSH private key
|
|
||||||
shell: >
|
|
||||||
echo -e 'n' |
|
|
||||||
ssh-keygen -b 2048 -C {{ SSH_keys.comment }}
|
|
||||||
-t rsa -f {{ SSH_keys.private }} -q -N ""
|
|
||||||
args:
|
|
||||||
creates: "{{ SSH_keys.private }}"
|
|
||||||
|
|
||||||
- name: Generate the SSH public key
|
|
||||||
shell: >
|
|
||||||
echo `ssh-keygen -y -f {{ SSH_keys.private }}` {{ SSH_keys.comment }}
|
|
||||||
> {{ SSH_keys.public }}
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Change mode for the SSH private key
|
|
||||||
file:
|
|
||||||
path: "{{ SSH_keys.private }}"
|
|
||||||
mode: 0600
|
|
||||||
|
|
||||||
- name: Ensure the dynamic inventory exists
|
|
||||||
blockinfile:
|
|
||||||
dest: configs/inventory.dynamic
|
|
||||||
marker: "# {mark} ALGO MANAGED BLOCK"
|
|
||||||
create: true
|
|
||||||
block: |
|
|
||||||
[algo:children]
|
|
||||||
{% for group in cloud_providers.keys() %}
|
|
||||||
{{ group }}
|
|
||||||
{% endfor %}
|
|
@ -1,12 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- name: Ensure the local ssh directory is exist
|
|
||||||
file:
|
|
||||||
path: ~/.ssh/
|
|
||||||
state: directory
|
|
||||||
|
|
||||||
- name: Copy the algo ssh key to the local ssh directory
|
|
||||||
copy:
|
|
||||||
src: "{{ SSH_keys.private }}"
|
|
||||||
dest: ~/.ssh/algo.pem
|
|
||||||
mode: '0600'
|
|
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- name: Wait until SSH becomes ready...
|
|
||||||
wait_for:
|
|
||||||
port: 22
|
|
||||||
host: "{{ cloud_instance_ip }}"
|
|
||||||
search_regex: "OpenSSH"
|
|
||||||
delay: 10
|
|
||||||
timeout: 320
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: A short pause, in order to be sure the instance is ready
|
|
||||||
pause:
|
|
||||||
seconds: 20
|
|
||||||
|
|
||||||
- include_tasks: local_ssh.yml
|
|
@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- name: Ubuntu | Install prerequisites
|
|
||||||
raw: "{{ item }}"
|
|
||||||
with_items:
|
|
||||||
- sleep 10
|
|
||||||
- apt-get update -qq
|
|
||||||
- apt-get install -qq -y python2.7 sudo
|
|
||||||
become: true
|
|
||||||
|
|
||||||
- name: Ubuntu | Configure defaults
|
|
||||||
raw: sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
|
|
||||||
tags:
|
|
||||||
- update-alternatives
|
|
@ -0,0 +1,214 @@
|
|||||||
|
---
|
||||||
|
azure_regions: >
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"displayName": "East Asia",
|
||||||
|
"latitude": "22.267",
|
||||||
|
"longitude": "114.188",
|
||||||
|
"name": "eastasia",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Southeast Asia",
|
||||||
|
"latitude": "1.283",
|
||||||
|
"longitude": "103.833",
|
||||||
|
"name": "southeastasia",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Central US",
|
||||||
|
"latitude": "41.5908",
|
||||||
|
"longitude": "-93.6208",
|
||||||
|
"name": "centralus",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "East US",
|
||||||
|
"latitude": "37.3719",
|
||||||
|
"longitude": "-79.8164",
|
||||||
|
"name": "eastus",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "East US 2",
|
||||||
|
"latitude": "36.6681",
|
||||||
|
"longitude": "-78.3889",
|
||||||
|
"name": "eastus2",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "West US",
|
||||||
|
"latitude": "37.783",
|
||||||
|
"longitude": "-122.417",
|
||||||
|
"name": "westus",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "North Central US",
|
||||||
|
"latitude": "41.8819",
|
||||||
|
"longitude": "-87.6278",
|
||||||
|
"name": "northcentralus",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "South Central US",
|
||||||
|
"latitude": "29.4167",
|
||||||
|
"longitude": "-98.5",
|
||||||
|
"name": "southcentralus",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "North Europe",
|
||||||
|
"latitude": "53.3478",
|
||||||
|
"longitude": "-6.2597",
|
||||||
|
"name": "northeurope",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "West Europe",
|
||||||
|
"latitude": "52.3667",
|
||||||
|
"longitude": "4.9",
|
||||||
|
"name": "westeurope",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Japan West",
|
||||||
|
"latitude": "34.6939",
|
||||||
|
"longitude": "135.5022",
|
||||||
|
"name": "japanwest",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Japan East",
|
||||||
|
"latitude": "35.68",
|
||||||
|
"longitude": "139.77",
|
||||||
|
"name": "japaneast",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Brazil South",
|
||||||
|
"latitude": "-23.55",
|
||||||
|
"longitude": "-46.633",
|
||||||
|
"name": "brazilsouth",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Australia East",
|
||||||
|
"latitude": "-33.86",
|
||||||
|
"longitude": "151.2094",
|
||||||
|
"name": "australiaeast",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Australia Southeast",
|
||||||
|
"latitude": "-37.8136",
|
||||||
|
"longitude": "144.9631",
|
||||||
|
"name": "australiasoutheast",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "South India",
|
||||||
|
"latitude": "12.9822",
|
||||||
|
"longitude": "80.1636",
|
||||||
|
"name": "southindia",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Central India",
|
||||||
|
"latitude": "18.5822",
|
||||||
|
"longitude": "73.9197",
|
||||||
|
"name": "centralindia",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "West India",
|
||||||
|
"latitude": "19.088",
|
||||||
|
"longitude": "72.868",
|
||||||
|
"name": "westindia",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Canada Central",
|
||||||
|
"latitude": "43.653",
|
||||||
|
"longitude": "-79.383",
|
||||||
|
"name": "canadacentral",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Canada East",
|
||||||
|
"latitude": "46.817",
|
||||||
|
"longitude": "-71.217",
|
||||||
|
"name": "canadaeast",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "UK South",
|
||||||
|
"latitude": "50.941",
|
||||||
|
"longitude": "-0.799",
|
||||||
|
"name": "uksouth",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "UK West",
|
||||||
|
"latitude": "53.427",
|
||||||
|
"longitude": "-3.084",
|
||||||
|
"name": "ukwest",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "West Central US",
|
||||||
|
"latitude": "40.890",
|
||||||
|
"longitude": "-110.234",
|
||||||
|
"name": "westcentralus",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "West US 2",
|
||||||
|
"latitude": "47.233",
|
||||||
|
"longitude": "-119.852",
|
||||||
|
"name": "westus2",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Korea Central",
|
||||||
|
"latitude": "37.5665",
|
||||||
|
"longitude": "126.9780",
|
||||||
|
"name": "koreacentral",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Korea South",
|
||||||
|
"latitude": "35.1796",
|
||||||
|
"longitude": "129.0756",
|
||||||
|
"name": "koreasouth",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "France Central",
|
||||||
|
"latitude": "46.3772",
|
||||||
|
"longitude": "2.3730",
|
||||||
|
"name": "francecentral",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "France South",
|
||||||
|
"latitude": "43.8345",
|
||||||
|
"longitude": "2.1972",
|
||||||
|
"name": "francesouth",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Australia Central",
|
||||||
|
"latitude": "-35.3075",
|
||||||
|
"longitude": "149.1244",
|
||||||
|
"name": "australiacentral",
|
||||||
|
"subscriptionId": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"displayName": "Australia Central 2",
|
||||||
|
"latitude": "-35.3075",
|
||||||
|
"longitude": "149.1244",
|
||||||
|
"name": "australiacentral2",
|
||||||
|
"subscriptionId": null
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your azure secret id (https://github.com/trailofbits/algo/blob/master/docs/cloud-azure.md)
|
||||||
|
You can skip this step if you want to use your defaults credentials from ~/.azure/credentials
|
||||||
|
echo: false
|
||||||
|
register: _azure_secret
|
||||||
|
when:
|
||||||
|
- azure_secret is undefined
|
||||||
|
- lookup('env','AZURE_SECRET')|length <= 0
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your azure tenant id (https://github.com/trailofbits/algo/blob/master/docs/cloud-azure.md)
|
||||||
|
You can skip this step if you want to use your defaults credentials from ~/.azure/credentials
|
||||||
|
echo: false
|
||||||
|
register: _azure_tenant
|
||||||
|
when:
|
||||||
|
- azure_tenant is undefined
|
||||||
|
- lookup('env','AZURE_TENANT')|length <= 0
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your azure client id (application id) (https://github.com/trailofbits/algo/blob/master/docs/cloud-azure.md)
|
||||||
|
You can skip this step if you want to use your defaults credentials from ~/.azure/credentials
|
||||||
|
echo: false
|
||||||
|
register: _azure_client_id
|
||||||
|
when:
|
||||||
|
- azure_client_id is undefined
|
||||||
|
- lookup('env','AZURE_CLIENT_ID')|length <= 0
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your azure subscription id (https://github.com/trailofbits/algo/blob/master/docs/cloud-azure.md)
|
||||||
|
You can skip this step if you want to use your defaults credentials from ~/.azure/credentials
|
||||||
|
echo: false
|
||||||
|
register: _azure_subscription_id
|
||||||
|
when:
|
||||||
|
- azure_subscription_id is undefined
|
||||||
|
- lookup('env','AZURE_SUBSCRIPTION_ID')|length <= 0
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
secret: "{{ azure_secret | default(_azure_secret.user_input|default(None)) | default(lookup('env','AZURE_SECRET'), true) }}"
|
||||||
|
tenant: "{{ azure_tenant | default(_azure_tenant.user_input|default(None)) | default(lookup('env','AZURE_TENANT'), true) }}"
|
||||||
|
client_id: "{{ azure_client_id | default(_azure_client_id.user_input|default(None)) | default(lookup('env','AZURE_CLIENT_ID'), true) }}"
|
||||||
|
subscription_id: "{{ azure_subscription_id | default(_azure_subscription_id.user_input|default(None)) | default(lookup('env','AZURE_SUBSCRIPTION_ID'), true) }}"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Set facts about the regions
|
||||||
|
set_fact:
|
||||||
|
aws_regions: "{{ azure_regions | sort(attribute='region_name') }}"
|
||||||
|
|
||||||
|
- name: Set the default region
|
||||||
|
set_fact:
|
||||||
|
default_region: >-
|
||||||
|
{% for r in aws_regions %}
|
||||||
|
{%- if r['region_name'] == "us-east-1" %}{{ loop.index }}{% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
What region should the server be located in?
|
||||||
|
{% for r in aws_regions %}
|
||||||
|
{{ loop.index }}. {{ r['region_name'] }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Enter the number of your desired region
|
||||||
|
[{{ default_region }}]
|
||||||
|
register: _algo_region
|
||||||
|
when: region is undefined
|
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your API token. The token must have read and write permissions (https://cloud.digitalocean.com/settings/api/tokens):
|
||||||
|
echo: false
|
||||||
|
register: _do_token
|
||||||
|
when:
|
||||||
|
- do_token is undefined
|
||||||
|
- lookup('env','DO_API_TOKEN')|length <= 0
|
||||||
|
|
||||||
|
- name: Set the token as a fact
|
||||||
|
set_fact:
|
||||||
|
algo_do_token: "{{ do_token | default(_do_token.user_input|default(None)) | default(lookup('env','DO_API_TOKEN'), true) }}"
|
||||||
|
|
||||||
|
- name: Get regions
|
||||||
|
uri:
|
||||||
|
url: https://api.digitalocean.com/v2/regions
|
||||||
|
method: GET
|
||||||
|
status_code: 200
|
||||||
|
headers:
|
||||||
|
Content-Type: "application/json"
|
||||||
|
Authorization: "Bearer {{ algo_do_token }}"
|
||||||
|
register: _do_regions
|
||||||
|
|
||||||
|
- name: Set facts about thre regions
|
||||||
|
set_fact:
|
||||||
|
do_regions: "{{ _do_regions.json.regions | sort(attribute='slug') }}"
|
||||||
|
|
||||||
|
- name: Set default region
|
||||||
|
set_fact:
|
||||||
|
default_region: >-
|
||||||
|
{% for r in do_regions %}
|
||||||
|
{%- if r['slug'] == "nyc3" %}{{ loop.index }}{% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
What region should the server be located in?
|
||||||
|
{% for r in do_regions %}
|
||||||
|
{{ loop.index }}. {{ r['slug'] }} {{ r['name'] }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Enter the number of your desired region
|
||||||
|
[{{ default_region }}]
|
||||||
|
register: _algo_region
|
||||||
|
when: region is undefined
|
@ -1,6 +0,0 @@
|
|||||||
iface eth0 inet6 static
|
|
||||||
address {{ item.ip_address }}
|
|
||||||
netmask {{ item.netmask }}
|
|
||||||
gateway {{ item.gateway }}
|
|
||||||
autoconf 0
|
|
||||||
dns-nameservers 2001:4860:4860::8844 2001:4860:4860::8888
|
|
@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
|
ami_search_encrypted: omit
|
||||||
|
encrypted: "{{ cloud_providers.ec2.encrypted }}"
|
||||||
ec2_vpc_nets:
|
ec2_vpc_nets:
|
||||||
cidr_block: 172.16.0.0/16
|
cidr_block: 172.16.0.0/16
|
||||||
subnet_cidr: 172.16.254.0/23
|
subnet_cidr: 172.16.254.0/23
|
||||||
|
@ -1,37 +1,27 @@
|
|||||||
|
---
|
||||||
- name: Check if the encrypted image already exist
|
- name: Check if the encrypted image already exist
|
||||||
ec2_ami_find:
|
ec2_ami_facts:
|
||||||
aws_access_key: "{{ aws_access_key | default(lookup('env','AWS_ACCESS_KEY_ID'), true)}}"
|
aws_access_key: "{{ access_key }}"
|
||||||
aws_secret_key: "{{ aws_secret_key | default(lookup('env','AWS_SECRET_ACCESS_KEY'), true)}}"
|
aws_secret_key: "{{ secret_key }}"
|
||||||
owner: self
|
owners: self
|
||||||
sort: creationDate
|
region: "{{ algo_region }}"
|
||||||
sort_order: descending
|
filters:
|
||||||
sort_end: 1
|
state: available
|
||||||
state: available
|
"tag:Algo": encrypted
|
||||||
ami_tags:
|
|
||||||
Algo: "encrypted"
|
|
||||||
region: "{{ region }}"
|
|
||||||
register: search_crypt
|
register: search_crypt
|
||||||
|
|
||||||
- set_fact:
|
|
||||||
ami_image: "{{ search_crypt.results[0].ami_id }}"
|
|
||||||
when: search_crypt.results
|
|
||||||
|
|
||||||
- name: Copy to an encrypted image
|
- name: Copy to an encrypted image
|
||||||
ec2_ami_copy:
|
ec2_ami_copy:
|
||||||
aws_access_key: "{{ aws_access_key | default(lookup('env','AWS_ACCESS_KEY_ID'), true)}}"
|
aws_access_key: "{{ access_key }}"
|
||||||
aws_secret_key: "{{ aws_secret_key | default(lookup('env','AWS_SECRET_ACCESS_KEY'), true)}}"
|
aws_secret_key: "{{ secret_key }}"
|
||||||
encrypted: yes
|
encrypted: yes
|
||||||
name: algo
|
name: algo
|
||||||
kms_key_id: "{{ kms_key_id | default(omit) }}"
|
kms_key_id: "{{ kms_key_id | default(omit) }}"
|
||||||
region: "{{ region }}"
|
region: "{{ algo_region }}"
|
||||||
source_image_id: "{{ ami_image }}"
|
source_image_id: "{{ (ami_search.images | sort(attribute='creation_date') | last)['image_id'] }}"
|
||||||
source_region: "{{ region }}"
|
source_region: "{{ algo_region }}"
|
||||||
|
wait: true
|
||||||
tags:
|
tags:
|
||||||
Algo: "encrypted"
|
Algo: "encrypted"
|
||||||
wait: true
|
register: ami_search_encrypted
|
||||||
register: enc_image
|
when: search_crypt.images|length|int == 0
|
||||||
when: not search_crypt.results
|
|
||||||
|
|
||||||
- set_fact:
|
|
||||||
ami_image: "{{ enc_image.image_id }}"
|
|
||||||
when: not search_crypt.results
|
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your aws_access_key (http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html)
|
||||||
|
Note: Make sure to use an IAM user with an acceptable policy attached (see https://github.com/trailofbits/algo/blob/master/docs/deploy-from-ansible.md)
|
||||||
|
echo: false
|
||||||
|
register: _aws_access_key
|
||||||
|
when:
|
||||||
|
- aws_access_key is undefined
|
||||||
|
- lookup('env','AWS_ACCESS_KEY_ID')|length <= 0
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your aws_secret_key (http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html)
|
||||||
|
echo: false
|
||||||
|
register: _aws_secret_key
|
||||||
|
when:
|
||||||
|
- aws_secret_key is undefined
|
||||||
|
- lookup('env','AWS_SECRET_ACCESS_KEY')|length <= 0
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
access_key: "{{ aws_access_key | default(_aws_access_key.user_input|default(None)) | default(lookup('env','AWS_ACCESS_KEY_ID'), true) }}"
|
||||||
|
secret_key: "{{ aws_secret_key | default(_aws_secret_key.user_input|default(None)) | default(lookup('env','AWS_SECRET_ACCESS_KEY'), true) }}"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Get regions
|
||||||
|
aws_region_facts:
|
||||||
|
aws_access_key: "{{ access_key }}"
|
||||||
|
aws_secret_key: "{{ secret_key }}"
|
||||||
|
region: us-east-1
|
||||||
|
register: _aws_regions
|
||||||
|
|
||||||
|
- name: Set facts about the regions
|
||||||
|
set_fact:
|
||||||
|
aws_regions: "{{ _aws_regions.regions | sort(attribute='region_name') }}"
|
||||||
|
|
||||||
|
- name: Set the default region
|
||||||
|
set_fact:
|
||||||
|
default_region: >-
|
||||||
|
{% for r in aws_regions %}
|
||||||
|
{%- if r['region_name'] == "us-east-1" %}{{ loop.index }}{% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
What region should the server be located in?
|
||||||
|
(https://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region)
|
||||||
|
{% for r in aws_regions %}
|
||||||
|
{{ loop.index }}. {{ r['region_name'] }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Enter the number of your desired region
|
||||||
|
[{{ default_region }}]
|
||||||
|
register: _algo_region
|
||||||
|
when: region is undefined
|
@ -0,0 +1,67 @@
|
|||||||
|
---
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter the local path to your credentials JSON file
|
||||||
|
(https://support.google.com/cloud/answer/6158849?hl=en&ref_topic=6262490#serviceaccounts)
|
||||||
|
register: _gce_credentials_file
|
||||||
|
when:
|
||||||
|
- gce_credentials_file is undefined
|
||||||
|
- lookup('env','GCE_CREDENTIALS_FILE_PATH')|length <= 0
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
credentials_file_path: "{{ gce_credentials_file | default(_gce_credentials_file.user_input|default(None)) | default(lookup('env','GCE_CREDENTIALS_FILE_PATH'), true) }}"
|
||||||
|
ssh_public_key_lookup: "{{ lookup('file', '{{ SSH_keys.public }}') }}"
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
credentials_file_lookup: "{{ lookup('file', '{{ credentials_file_path }}') }}"
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
service_account_email: "{{ credentials_file_lookup.client_email | default(lookup('env','GCE_EMAIL')) }}"
|
||||||
|
project_id: "{{ credentials_file_lookup.project_id | default(lookup('env','GCE_PROJECT')) }}"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Get regions
|
||||||
|
gce_region_facts:
|
||||||
|
service_account_email: "{{ credentials_file_lookup.client_email }}"
|
||||||
|
credentials_file: "{{ credentials_file_path }}"
|
||||||
|
project_id: "{{ credentials_file_lookup.project_id }}"
|
||||||
|
register: _gce_regions
|
||||||
|
|
||||||
|
- name: Set facts about the regions
|
||||||
|
set_fact:
|
||||||
|
gce_regions: >-
|
||||||
|
[{%- for region in _gce_regions.results.regions | sort(attribute='name') -%}
|
||||||
|
{% if region.status == "UP" %}
|
||||||
|
{% for zone in region.zones | sort(attribute='name') %}
|
||||||
|
{% if zone.status == "UP" %}
|
||||||
|
'{{ zone.name }}'
|
||||||
|
{% endif %}{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}{% if not loop.last %},{% endif %}
|
||||||
|
{%- endfor -%}]
|
||||||
|
|
||||||
|
- name: Set facts about the default region
|
||||||
|
set_fact:
|
||||||
|
default_region: >-
|
||||||
|
{% for region in gce_regions %}
|
||||||
|
{%- if region == "us-east1-b" %}{{ loop.index }}{% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
What region should the server be located in?
|
||||||
|
(https://cloud.google.com/compute/docs/regions-zones/)
|
||||||
|
{% for r in gce_regions %}
|
||||||
|
{{ loop.index }}. {{ r }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Enter the number of your desired region
|
||||||
|
[{{ default_region }}]
|
||||||
|
register: _gce_region
|
||||||
|
when: region is undefined
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
algo_region: >-
|
||||||
|
{% if region is defined %}{{ region }}
|
||||||
|
{%- elif _gce_region.user_input is defined and _gce_region.user_input != "" %}{{ gce_regions[_gce_region.user_input | int -1 ] }}
|
||||||
|
{%- else %}{{ gce_regions[default_region | int - 1] }}{% endif %}
|
@ -0,0 +1,60 @@
|
|||||||
|
---
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your aws_access_key (http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html)
|
||||||
|
Note: Make sure to use an IAM user with an acceptable policy attached (see https://github.com/trailofbits/algo/blob/master/docs/deploy-from-ansible.md)
|
||||||
|
echo: false
|
||||||
|
register: _aws_access_key
|
||||||
|
when:
|
||||||
|
- aws_access_key is undefined
|
||||||
|
- lookup('env','AWS_ACCESS_KEY_ID')|length <= 0
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your aws_secret_key (http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html)
|
||||||
|
echo: false
|
||||||
|
register: _aws_secret_key
|
||||||
|
when:
|
||||||
|
- aws_secret_key is undefined
|
||||||
|
- lookup('env','AWS_SECRET_ACCESS_KEY')|length <= 0
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
access_key: "{{ aws_access_key | default(_aws_access_key.user_input|default(None)) | default(lookup('env','AWS_ACCESS_KEY_ID'), true) }}"
|
||||||
|
secret_key: "{{ aws_secret_key | default(_aws_secret_key.user_input|default(None)) | default(lookup('env','AWS_SECRET_ACCESS_KEY'), true) }}"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Get regions
|
||||||
|
lightsail_region_facts:
|
||||||
|
aws_access_key: "{{ access_key }}"
|
||||||
|
aws_secret_key: "{{ secret_key }}"
|
||||||
|
register: _lightsail_regions
|
||||||
|
|
||||||
|
- name: Set facts about thre regions
|
||||||
|
set_fact:
|
||||||
|
lightsail_regions: "{{ _lightsail_regions.results.regions | sort(attribute='name') }}"
|
||||||
|
|
||||||
|
- name: Set the default region
|
||||||
|
set_fact:
|
||||||
|
default_region: >-
|
||||||
|
{% for r in lightsail_regions %}
|
||||||
|
{%- if r['name'] == "eu-west-1" %}{{ loop.index }}{% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
What region should the server be located in?
|
||||||
|
(https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/)
|
||||||
|
{% for r in lightsail_regions %}
|
||||||
|
{{ loop.index }}. {{ r['name'] }} {{ r['displayName'] }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Enter the number of your desired region
|
||||||
|
[{{ default_region }}]
|
||||||
|
register: _algo_region
|
||||||
|
when: region is undefined
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
algo_region: >-
|
||||||
|
{% if region is defined %}{{ region }}
|
||||||
|
{%- elif _algo_region.user_input is defined and _algo_region.user_input != "" %}{{ lightsail_regions[_algo_region.user_input | int -1 ]['name'] }}
|
||||||
|
{%- else %}{{ lightsail_regions[default_region | int - 1]['name'] }}{% endif %}
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
scaleway_regions:
|
||||||
|
- alias: par1
|
||||||
|
- alias: ams1
|
@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your auth token (https://www.scaleway.com/docs/generate-an-api-token/)
|
||||||
|
echo: false
|
||||||
|
register: _scaleway_token
|
||||||
|
when: scaleway_token is undefined
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter your organization name (https://cloud.scaleway.com/#/billing)
|
||||||
|
register: _scaleway_org
|
||||||
|
when: scaleway_org is undefined
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
What region should the server be located in?
|
||||||
|
{% for r in scaleway_regions %}
|
||||||
|
{{ loop.index }}. {{ r['alias'] }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Enter the number of your desired region
|
||||||
|
[{{ scaleway_regions.0.alias }}]
|
||||||
|
register: _algo_region
|
||||||
|
when: region is undefined
|
||||||
|
|
||||||
|
- name: Set scaleway facts
|
||||||
|
set_fact:
|
||||||
|
algo_scaleway_token: "{{ scaleway_token | default(_scaleway_token.user_input) }}"
|
||||||
|
algo_scaleway_org: "{{ scaleway_org | default(_scaleway_org.user_input|default(omit)) }}"
|
||||||
|
algo_region: >-
|
||||||
|
{% if region is defined %}{{ region }}
|
||||||
|
{%- elif _algo_region.user_input is defined and _algo_region.user_input != "" %}{{ scaleway_regions[_algo_region.user_input | int -1 ]['alias'] }}
|
||||||
|
{%- else %}{{ scaleway_regions.0.alias }}{% endif %}
|
@ -0,0 +1,36 @@
|
|||||||
|
- block:
|
||||||
|
- name: Include prompts
|
||||||
|
import_tasks: prompts.yml
|
||||||
|
|
||||||
|
- name: Upload the SSH key
|
||||||
|
vr_ssh_key:
|
||||||
|
name: "{{ SSH_keys.comment }}"
|
||||||
|
ssh_key: "{{ lookup('file', '{{ SSH_keys.public }}') }}"
|
||||||
|
register: ssh_key
|
||||||
|
|
||||||
|
- name: Creating a server
|
||||||
|
vr_server:
|
||||||
|
name: "{{ algo_server_name }}"
|
||||||
|
hostname: "{{ algo_server_name }}"
|
||||||
|
os: "{{ cloud_providers.vultr.os }}"
|
||||||
|
plan: "{{ cloud_providers.vultr.size }}"
|
||||||
|
region: "{{ algo_vultr_region }}"
|
||||||
|
state: started
|
||||||
|
tag: Environment:Algo
|
||||||
|
ssh_key: "{{ ssh_key.vultr_ssh_key.name }}"
|
||||||
|
ipv6_enabled: true
|
||||||
|
auto_backup_enabled: false
|
||||||
|
notify_activate: false
|
||||||
|
register: vultr_server
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
cloud_instance_ip: "{{ vultr_server.vultr_server.v4_main_ip }}"
|
||||||
|
ansible_ssh_user: root
|
||||||
|
|
||||||
|
environment:
|
||||||
|
VULTR_API_CONFIG: "{{ algo_vultr_config }}"
|
||||||
|
rescue:
|
||||||
|
- debug: var=fail_hint
|
||||||
|
tags: always
|
||||||
|
- fail:
|
||||||
|
tags: always
|
@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter the local path to your configuration INI file
|
||||||
|
(https://github.com/trailofbits/algo/docs/cloud-vultr.md):
|
||||||
|
register: _vultr_config
|
||||||
|
when: vultr_config is undefined
|
||||||
|
|
||||||
|
- name: Set the token as a fact
|
||||||
|
set_fact:
|
||||||
|
algo_vultr_config: "{{ vultr_config | default(_vultr_config.user_input) | default(lookup('env','VULTR_API_CONFIG'), true) }}"
|
||||||
|
|
||||||
|
- name: Get regions
|
||||||
|
uri:
|
||||||
|
url: https://api.vultr.com/v1/regions/list
|
||||||
|
method: GET
|
||||||
|
status_code: 200
|
||||||
|
register: _vultr_regions
|
||||||
|
|
||||||
|
- name: Format regions
|
||||||
|
set_fact:
|
||||||
|
regions: >-
|
||||||
|
[ {% for k, v in _vultr_regions.json.items() %}
|
||||||
|
{{ v }}{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %} ]
|
||||||
|
|
||||||
|
- name: Set regions as a fact
|
||||||
|
set_fact:
|
||||||
|
vultr_regions: "{{ regions | sort(attribute='country') }}"
|
||||||
|
|
||||||
|
- name: Set default region
|
||||||
|
set_fact:
|
||||||
|
default_region: >-
|
||||||
|
{% for r in vultr_regions %}
|
||||||
|
{%- if r['DCID'] == "1" %}{{ loop.index }}{% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
What region should the server be located in?
|
||||||
|
(https://www.vultr.com/locations/):
|
||||||
|
{% for r in vultr_regions %}
|
||||||
|
{{ loop.index }}. {{ r['name'] }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
Enter the number of your desired region
|
||||||
|
[{{ default_region }}]
|
||||||
|
register: _algo_region
|
||||||
|
when: region is undefined
|
||||||
|
|
||||||
|
- name: Set the desired region as a fact
|
||||||
|
set_fact:
|
||||||
|
algo_vultr_region: >-
|
||||||
|
{% if region is defined %}{{ region }}
|
||||||
|
{%- elif _algo_region.user_input is defined and _algo_region.user_input != "" %}{{ vultr_regions[_algo_region.user_input | int -1 ]['name'] }}
|
||||||
|
{%- else %}{{ vultr_regions[default_region | int - 1]['name'] }}{% endif %}
|
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
- block:
|
||||||
|
- name: Generate password for the CA key
|
||||||
|
local_action:
|
||||||
|
module: shell
|
||||||
|
openssl rand -hex 16
|
||||||
|
register: CA_password
|
||||||
|
|
||||||
|
- name: Generate p12 export password
|
||||||
|
local_action:
|
||||||
|
module: shell
|
||||||
|
openssl rand 8 | python -c 'import sys,string; chars=string.ascii_letters + string.digits + "_@"; print "".join([chars[ord(c) % 64] for c in list(sys.stdin.read())])'
|
||||||
|
register: p12_password_generated
|
||||||
|
when: p12_password is not defined
|
||||||
|
tags: update-users
|
||||||
|
become: false
|
||||||
|
|
||||||
|
- name: Define facts
|
||||||
|
set_fact:
|
||||||
|
p12_export_password: "{{ p12_password|default(p12_password_generated.stdout) }}"
|
||||||
|
tags: update-users
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
CA_password: "{{ CA_password.stdout }}"
|
||||||
|
IP_subject_alt_name: "{{ IP_subject_alt_name }}"
|
||||||
|
ipv6_support: "{% if ansible_default_ipv6['gateway'] is defined %}true{% else %}false{% endif %}"
|
@ -1,7 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
- { role: common, tags: common }
|
|
||||||
- role: dns_encryption
|
|
||||||
tags: dns_encryption
|
|
||||||
when: dns_encryption == true
|
|
@ -1,7 +1,9 @@
|
|||||||
---
|
---
|
||||||
listen_port: "{% if local_dns|d(false)|bool == true %}5353{% else %}53{% endif %}"
|
algo_local_dns: false
|
||||||
|
listen_port: "{% if algo_local_dns %}5353{% else %}53{% endif %}"
|
||||||
# the version used if the latest unavailable (in case of Github API rate limited)
|
# the version used if the latest unavailable (in case of Github API rate limited)
|
||||||
dnscrypt_proxy_version: 2.0.10
|
dnscrypt_proxy_version: 2.0.10
|
||||||
apparmor_enabled: true
|
apparmor_enabled: true
|
||||||
dns_encryption: true
|
dns_encryption: true
|
||||||
dns_encryption_provider: "*"
|
dns_encryption_provider: "*"
|
||||||
|
ipv6_support: false
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
dependencies:
|
|
||||||
- role: common
|
|
||||||
tags: common
|
|
@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter the IP address of your server: (or use localhost for local installation):
|
||||||
|
[localhost]
|
||||||
|
register: _algo_server
|
||||||
|
when: server is undefined
|
||||||
|
|
||||||
|
- name: Set the facts
|
||||||
|
set_fact:
|
||||||
|
cloud_instance_ip: >-
|
||||||
|
{% if server is defined %}{{ server }}
|
||||||
|
{%- elif _algo_server.user_input is defined and _algo_server.user_input != "" %}{{ _algo_server.user_input }}
|
||||||
|
{%- else %}localhost{% endif %}
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
What user should we use to login on the server? (note: passwordless login required, or ignore if you're deploying to localhost)
|
||||||
|
[root]
|
||||||
|
register: _algo_ssh_user
|
||||||
|
when:
|
||||||
|
- ssh_user is undefined
|
||||||
|
- cloud_instance_ip != "localhost"
|
||||||
|
|
||||||
|
- name: Set the facts
|
||||||
|
set_fact:
|
||||||
|
ansible_ssh_user: >-
|
||||||
|
{% if ssh_user is defined %}{{ ssh_user }}
|
||||||
|
{%- elif _algo_ssh_user.user_input is defined and _algo_ssh_user.user_input != "" %}{{ _algo_ssh_user.user_input }}
|
||||||
|
{%- else %}root{% endif %}
|
||||||
|
|
||||||
|
- pause:
|
||||||
|
prompt: |
|
||||||
|
Enter the public IP address of your server: (IMPORTANT! This IP is used to verify the certificate)
|
||||||
|
[{{ cloud_instance_ip }}]
|
||||||
|
register: _endpoint
|
||||||
|
when: endpoint is undefined
|
||||||
|
|
||||||
|
- name: Set the facts
|
||||||
|
set_fact:
|
||||||
|
IP_subject_alt_name: >-
|
||||||
|
{% if endpoint is defined %}{{ endpoint }}
|
||||||
|
{%- elif _endpoint.user_input is defined and _endpoint.user_input != "" %}{{ _endpoint.user_input }}
|
||||||
|
{%- else %}{{ cloud_instance_ip }}{% endif %}
|
@ -1,4 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
- { role: common, tags: common }
|
|
@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
- { role: common, tags: common }
|
|
||||||
- role: dns_encryption
|
- role: dns_encryption
|
||||||
tags: dns_encryption
|
tags: dns_encryption
|
||||||
when: dns_encryption == true
|
when: dns_encryption
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Get the existing kernel parameters
|
|
||||||
command: sysctl -b kern.conftxt
|
|
||||||
register: kern_conftxt
|
|
||||||
when: rebuild_kernel is defined and rebuild_kernel == "true"
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Set the rebuild_needed fact
|
|
||||||
set_fact:
|
|
||||||
rebuild_needed: true
|
|
||||||
when: item not in kern_conftxt.stdout and rebuild_kernel is defined and rebuild_kernel == "true"
|
|
||||||
with_items:
|
|
||||||
- "IPSEC"
|
|
||||||
- "IPSEC_NAT_T"
|
|
||||||
- "crypto"
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Make the kernel config
|
|
||||||
shell: sysctl -b kern.conftxt > /tmp/IPSEC
|
|
||||||
when: rebuild_needed is defined and rebuild_needed == true
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Ensure the all options are enabled
|
|
||||||
lineinfile:
|
|
||||||
dest: /tmp/IPSEC
|
|
||||||
line: "{{ item }}"
|
|
||||||
insertbefore: BOF
|
|
||||||
with_items:
|
|
||||||
- "options IPSEC"
|
|
||||||
- "options IPSEC_NAT_T"
|
|
||||||
- "device crypto"
|
|
||||||
when: rebuild_needed is defined and rebuild_needed == true
|
|
||||||
|
|
||||||
- name: HardenedBSD | Determine the sources
|
|
||||||
set_fact:
|
|
||||||
sources_repo: https://github.com/HardenedBSD/hardenedBSD.git
|
|
||||||
sources_version: "hardened/{{ ansible_distribution_release.split('.')[0] }}-stable/master"
|
|
||||||
when: "'Hardened' in ansible_distribution_version"
|
|
||||||
|
|
||||||
- name: FreeBSD | Determine the sources
|
|
||||||
set_fact:
|
|
||||||
sources_repo: https://github.com/freebsd/freebsd.git
|
|
||||||
sources_version: "stable/{{ ansible_distribution_major_version }}"
|
|
||||||
when: "'Hardened' not in ansible_distribution_version"
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Increase the git postBuffer size
|
|
||||||
git_config:
|
|
||||||
name: http.postBuffer
|
|
||||||
scope: global
|
|
||||||
value: 1048576000
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: FreeBSD / HardenedBSD | Fetching the sources...
|
|
||||||
git:
|
|
||||||
repo: "{{ sources_repo }}"
|
|
||||||
dest: /usr/krnl_src
|
|
||||||
version: "{{ sources_version }}"
|
|
||||||
accept_hostkey: true
|
|
||||||
async: 1000
|
|
||||||
poll: 0
|
|
||||||
register: fetching_sources
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Fetching the sources...
|
|
||||||
async_status: jid={{ fetching_sources.ansible_job_id }}
|
|
||||||
when: rebuild_needed is defined and rebuild_needed == true
|
|
||||||
register: result
|
|
||||||
until: result.finished
|
|
||||||
retries: 600
|
|
||||||
delay: 30
|
|
||||||
rescue:
|
|
||||||
- debug: var=fetching_sources
|
|
||||||
|
|
||||||
- fail:
|
|
||||||
msg: "Something went wrong. Check the debug output above."
|
|
||||||
|
|
||||||
- block:
|
|
||||||
- name: FreeBSD / HardenedBSD | The kernel is being built...
|
|
||||||
shell: >
|
|
||||||
mv /tmp/IPSEC /usr/krnl_src/sys/{{ ansible_architecture }}/conf &&
|
|
||||||
make buildkernel KERNCONF=IPSEC &&
|
|
||||||
make installkernel KERNCONF=IPSEC
|
|
||||||
args:
|
|
||||||
chdir: /usr/krnl_src
|
|
||||||
executable: /usr/local/bin/bash
|
|
||||||
when: rebuild_needed is defined and rebuild_needed == true
|
|
||||||
async: 1000
|
|
||||||
poll: 0
|
|
||||||
register: building_kernel
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | The kernel is being built...
|
|
||||||
async_status: jid={{ building_kernel.ansible_job_id }}
|
|
||||||
when: rebuild_needed is defined and rebuild_needed == true
|
|
||||||
register: result
|
|
||||||
until: result.finished
|
|
||||||
retries: 600
|
|
||||||
delay: 30
|
|
||||||
rescue:
|
|
||||||
- debug: var=building_kernel
|
|
||||||
|
|
||||||
- fail:
|
|
||||||
msg: "Something went wrong. Check the debug output above."
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Reboot
|
|
||||||
shell: sleep 2 && shutdown -r now
|
|
||||||
args:
|
|
||||||
executable: /usr/local/bin/bash
|
|
||||||
when: rebuild_needed is defined and rebuild_needed == true
|
|
||||||
async: 1
|
|
||||||
poll: 0
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: FreeBSD / HardenedBSD | Enable strongswan
|
|
||||||
lineinfile:
|
|
||||||
dest: /etc/rc.conf
|
|
||||||
regexp: ^strongswan_enable=
|
|
||||||
line: 'strongswan_enable="YES"'
|
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
wireguard_config_path: "configs/{{ IP_subject_alt_name }}/wireguard/"
|
|
||||||
wireguard_interface: wg0
|
|
||||||
wireguard_network_ipv4:
|
|
||||||
subnet: 10.19.49.0
|
|
||||||
prefix: 24
|
|
||||||
gateway: 10.19.49.1
|
|
||||||
clients_range: 10.19.49
|
|
||||||
clients_start: 100
|
|
||||||
wireguard_network_ipv6:
|
|
||||||
subnet: 'fd9d:bc11:4021::'
|
|
||||||
prefix: 48
|
|
||||||
gateway: 'fd9d:bc11:4021::1'
|
|
||||||
clients_range: 'fd9d:bc11:4021::'
|
|
||||||
clients_start: 100
|
|
||||||
wireguard_vpn_network: "{{ wireguard_network_ipv4['subnet'] }}/{{ wireguard_network_ipv4['prefix'] }}"
|
|
||||||
wireguard_vpn_network_ipv6: "{{ wireguard_network_ipv6['subnet'] }}/{{ wireguard_network_ipv6['prefix'] }}"
|
|
||||||
easyrsa_reinit_existent: false
|
|
||||||
wireguard_dns_servers: >-
|
|
||||||
{% if local_dns|default(false)|bool or dns_encryption|default(false)|bool == true %}
|
|
||||||
{{ local_service_ip }}
|
|
||||||
{% else %}
|
|
||||||
{% for host in dns_servers.ipv4 %}{{ host }}{% if not loop.last %},{% endif %}{% endfor %}{% if ipv6_support %},{% for host in dns_servers.ipv6 %}{{ host }}{% if not loop.last %},{% endif %}{% endfor %}{% endif %}
|
|
||||||
{% endif %}
|
|
@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
dependencies:
|
|
||||||
- { role: common, tags: common }
|
|
@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
- name: Configure the server and install required software
|
||||||
|
hosts: vpn-host
|
||||||
|
gather_facts: false
|
||||||
|
tags: algo
|
||||||
|
become: true
|
||||||
|
vars_files:
|
||||||
|
- config.cfg
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- role: common
|
||||||
|
- role: dns_adblocking
|
||||||
|
when: algo_local_dns
|
||||||
|
tags: dns_adblocking
|
||||||
|
- role: ssh_tunneling
|
||||||
|
when: algo_ssh_tunneling
|
||||||
|
tags: ssh_tunneling
|
||||||
|
- role: vpn
|
||||||
|
tags: vpn
|
||||||
|
|
||||||
|
post_tasks:
|
||||||
|
- block:
|
||||||
|
- name: Delete the CA key
|
||||||
|
local_action:
|
||||||
|
module: file
|
||||||
|
path: "configs/{{ IP_subject_alt_name }}/pki/private/cakey.pem"
|
||||||
|
state: absent
|
||||||
|
become: false
|
||||||
|
when: not algo_store_cakey
|
||||||
|
|
||||||
|
- name: Dump the configuration
|
||||||
|
local_action:
|
||||||
|
module: copy
|
||||||
|
dest: "configs/{{ IP_subject_alt_name }}/config.yml"
|
||||||
|
content: |
|
||||||
|
server: {{ 'localhost' if inventory_hostname == 'localhost' else inventory_hostname }}
|
||||||
|
server_user: {{ ansible_ssh_user }}
|
||||||
|
{% if algo_provider != "local" %}
|
||||||
|
ansible_ssh_private_key_file: {{ ansible_ssh_private_key_file|default(SSH_keys.private) }}
|
||||||
|
{% endif %}
|
||||||
|
algo_provider: {{ algo_provider }}
|
||||||
|
algo_server_name: {{ algo_server_name }}
|
||||||
|
algo_ondemand_cellular: {{ algo_ondemand_cellular }}
|
||||||
|
algo_ondemand_wifi: {{ algo_ondemand_wifi }}
|
||||||
|
algo_ondemand_wifi_exclude: {{ algo_ondemand_wifi_exclude }}
|
||||||
|
algo_local_dns: {{ algo_local_dns }}
|
||||||
|
algo_ssh_tunneling: {{ algo_ssh_tunneling }}
|
||||||
|
algo_windows: {{ algo_windows }}
|
||||||
|
algo_store_cakey: {{ algo_store_cakey }}
|
||||||
|
IP_subject_alt_name: {{ IP_subject_alt_name }}
|
||||||
|
{% if tests|default(false)|bool %}ca_password: {{ CA_password }}{% endif %}
|
||||||
|
become: false
|
||||||
|
|
||||||
|
- debug:
|
||||||
|
msg:
|
||||||
|
- "{{ congrats.common.split('\n') }}"
|
||||||
|
- " {{ congrats.p12_pass }}"
|
||||||
|
- " {% if algo_store_cakey %}{{ congrats.ca_key_pass }}{% endif %}"
|
||||||
|
- " {% if algo_provider != 'local' %}{{ congrats.ssh_access }}{% endif %}"
|
||||||
|
tags: always
|
||||||
|
rescue:
|
||||||
|
- debug: var=fail_hint
|
||||||
|
tags: always
|
||||||
|
- fail:
|
||||||
|
tags: always
|
Loading…
Reference in New Issue