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:
|
||||
cidr_block: 172.16.0.0/16
|
||||
subnet_cidr: 172.16.254.0/23
|
||||
|
@ -1,37 +1,27 @@
|
||||
---
|
||||
- name: Check if the encrypted image already exist
|
||||
ec2_ami_find:
|
||||
aws_access_key: "{{ aws_access_key | default(lookup('env','AWS_ACCESS_KEY_ID'), true)}}"
|
||||
aws_secret_key: "{{ aws_secret_key | default(lookup('env','AWS_SECRET_ACCESS_KEY'), true)}}"
|
||||
owner: self
|
||||
sort: creationDate
|
||||
sort_order: descending
|
||||
sort_end: 1
|
||||
state: available
|
||||
ami_tags:
|
||||
Algo: "encrypted"
|
||||
region: "{{ region }}"
|
||||
ec2_ami_facts:
|
||||
aws_access_key: "{{ access_key }}"
|
||||
aws_secret_key: "{{ secret_key }}"
|
||||
owners: self
|
||||
region: "{{ algo_region }}"
|
||||
filters:
|
||||
state: available
|
||||
"tag:Algo": encrypted
|
||||
register: search_crypt
|
||||
|
||||
- set_fact:
|
||||
ami_image: "{{ search_crypt.results[0].ami_id }}"
|
||||
when: search_crypt.results
|
||||
|
||||
- name: Copy to an encrypted image
|
||||
ec2_ami_copy:
|
||||
aws_access_key: "{{ aws_access_key | default(lookup('env','AWS_ACCESS_KEY_ID'), true)}}"
|
||||
aws_secret_key: "{{ aws_secret_key | default(lookup('env','AWS_SECRET_ACCESS_KEY'), true)}}"
|
||||
aws_access_key: "{{ access_key }}"
|
||||
aws_secret_key: "{{ secret_key }}"
|
||||
encrypted: yes
|
||||
name: algo
|
||||
kms_key_id: "{{ kms_key_id | default(omit) }}"
|
||||
region: "{{ region }}"
|
||||
source_image_id: "{{ ami_image }}"
|
||||
source_region: "{{ region }}"
|
||||
region: "{{ algo_region }}"
|
||||
source_image_id: "{{ (ami_search.images | sort(attribute='creation_date') | last)['image_id'] }}"
|
||||
source_region: "{{ algo_region }}"
|
||||
wait: true
|
||||
tags:
|
||||
Algo: "encrypted"
|
||||
wait: true
|
||||
register: enc_image
|
||||
when: not search_crypt.results
|
||||
|
||||
- set_fact:
|
||||
ami_image: "{{ enc_image.image_id }}"
|
||||
when: not search_crypt.results
|
||||
register: ami_search_encrypted
|
||||
when: search_crypt.images|length|int == 0
|
||||
|
@ -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)
|
||||
dnscrypt_proxy_version: 2.0.10
|
||||
apparmor_enabled: true
|
||||
dns_encryption: true
|
||||
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:
|
||||
- { role: common, tags: common }
|
||||
- role: 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