chore(ansible): save outcomes of working with certificates, improve readability

This commit is contained in:
Michele Cereda
2024-09-21 14:59:47 +02:00
parent 513f869b1b
commit 79ddaed45a
5 changed files with 269 additions and 73 deletions

68
knowledge base/https.md Normal file
View File

@@ -0,0 +1,68 @@
# HTTPS
TODO
Intro
<!-- Remove this line to uncomment if used
## Table of contents <!-- omit in toc -->
1. [TL;DR](#tldr)
1. [Further readings](#further-readings)
1. [Sources](#sources)
## TL;DR
<!-- Uncomment if used
<details>
<summary>Setup</summary>
```sh
```
</details>
-->
<!-- Uncomment if used
<details>
<summary>Usage</summary>
```sh
```
</details>
-->
<!-- Uncomment if used
<details>
<summary>Real world use cases</summary>
```sh
```
</details>
-->
## Further readings
- [Website]
- [Main repository]
### Sources
- [How Does HTTPS Work? RSA Encryption Explained]
<!--
Reference
═╬═Time══
-->
<!-- In-article sections -->
<!-- Knowledge base -->
<!-- Files -->
<!-- Upstream -->
[main repository]: https://github.com/project/
[website]: https://website/
<!-- Others -->
[how does https work? rsa encryption explained]: https://tiptopsecurity.com/how-does-https-work-rsa-encryption-explained/

View File

@@ -1,7 +1,5 @@
# OpenSSL
## Table of contents <!-- omit in toc -->
1. [TL;DR](#tldr)
1. [Create a self signed certificate](#create-a-self-signed-certificate)
1. [Display the contents of a SSL certificate](#display-the-contents-of-a-ssl-certificate)
@@ -47,6 +45,7 @@ openssl req -text -noout -verify -in 'request.csr'
# Check existing keys and verify their consistency.
openssl rsa -check -in 'file.key'
openssl rsa -check -in 'file.key' -noout
# Check certificates or keys and return information about them.
openssl x509 -text -noout -in 'certificate.crt'
@@ -123,7 +122,8 @@ To avoid answering the questions (for automation), add
```sh
$ openssl req -x509 -out 'cert.pem' \
-newkey 'rsa:4096' -keyout 'key.pem' -days '365' -nodes -subj "/C=NL/ST=Nederlands/L=Amsterdam/O=Mek Net/OU=Org/CN=mek.info"
-newkey 'rsa:4096' -keyout 'key.pem' -days '365' -nodes \
-subj "/C=NL/ST=Nederlands/L=Amsterdam/O=Mek Net/OU=Org/CN=mek.info"
Generating a 4096 bit RSA private key
..............................................................................................................................................................................................................................++
...........................................................................................................................................................................++

View File

@@ -60,3 +60,9 @@ ansible-vault view 'ssh.key.pub' --vault-password-file 'password_file.txt'
ansible-vault edit 'ssh.key.pub'
ANSIBLE_VAULT_PASSWORD_FILE='password_file.txt' ansible-vault decrypt --output '.ssh/id_rsa' 'ssh.key'
diff 'some_role/files/ssh.key.plain' <(ansible-vault view --vault-password-file 'password_file.txt' 'some_role/files/ssh.key.enc')
# List available 'lookup' plugins.
ansible-doc -t 'lookup' -l
# Show plugin-specific docs and examples.
ansible-doc -t 'lookup' 'fileglob'

View File

@@ -1,5 +1,22 @@
---
- name: Debug tasks
block:
- ansible.builtin.debug:
msg: I always display!
- ansible.builtin.debug:
msg: I only display with 'ansible-playbook -vvv' or with more 'v's
verbosity: 3
- debugger: on_failed
ansible.builtin.fail:
msg: Manual, enforced failure
# print all variables at this point => p task_vars
# continue => c
# abort and quit => q
- name: Flush handlers
ansible.builtin.meta: flush_handlers
- name: Retry tasks
ansible.builtin.command: /usr/bin/false
retries: 3
@@ -7,12 +24,73 @@
register: command_result
until: command_result is not failed
- name: Run tasks locally
delegate_to: 127.0.0.1 # 'localhost' works too
ansible.builtin.command: hostname
- name: Assertions
ansible.builtin.assert:
that:
- "'package' in ['container', 'package']"
- "'https://www.google.com/' is ansible.builtin.url"
- "'domain.example.com' is community.general.fqdn_valid(min_labels=2)"
fail_msg: What to say if any of the above conditions fail
success_msg: What to say if all of the above conditions succeed
- name: Test types
ansible.builtin.assert:
that:
# strings are classified as 'string', 'iterable' and 'sequence', but not 'mapping'
- "'aa' is string"
- "'aa' is iterable"
- "'aa' is sequence"
# numbers are classified as 'numbers', with 'integer' and 'float' being subclasses
- 42 is number and 5 is integer
- 21.34 is number and 12.1 is float
# lists are classified as 'iterable' and 'sequence', but not as 'string' nor 'mapping'
- "['list'] is iterable"
- "['list'] is sequence"
# dictionaries are classified as 'iterable', 'sequence' and 'mapping', but not as 'string'
- "{'a': 'dict'} is iterable"
- "{'a': 'dict'} is sequence"
- "{'a': 'dict'} is mapping"
# native booleans
- true is boolean
- True is boolean
- false is boolean
- False is boolean
- name: Type conversion
ansible.builtin.assert:
that:
- "'string' | int is integer"
- "'string' | float is float"
- 12 | float is float
- 21.02 | int is integer
- 43 | string is string
- 74.93 | string is string
- 4 | bool is boolean
- name: Elvis operator
# (condition) | bool | ternary(value_for_true_condition, value_for_false_condition, optional_value_for_null_condition)
ansible.builtin.set_fact:
acme_directory: >-
{{
this_is_a_test_run
| default(true)
| bool
| ternary(
'https://acme-staging-v02.api.letsencrypt.org/directory',
'https://acme-v02.api.letsencrypt.org/directory'
)
}}
- name: Create directories recursively
ansible.builtin.file:
path: /tmp/path/to/final/dir
state: directory
- name: Write files from tasks
- name: Define files content in tasks
ansible.builtin.copy:
dest: "{{ ansible_user_dir }}/.tmux.conf"
mode: u=rw,go=r
@@ -20,12 +98,23 @@
- name: Show input data type
set_fact:
ansible.builtin.set_fact:
should_be_string: "{{ 'this' | type_debug }}"
- name: Run locally
delegate_to: 127.0.0.1 # 'localhost' works too
command: hostname
- name: Pretty print information
ansible.builtin.debug:
msg: >-
{{
dict([
[ 'install_method', install_method ],
[ 'install_method in supported_install_methods', install_method in supported_install_methods ],
])
}}
- name: Use filters
tags: filter
ansible.builtin.set_fact:
path_list_of_all_txt_files_in_dir: "{{ lookup('ansible.builtin.fileglob', '/my/path/*.txt') }}"
- name: Import tasks
block:
@@ -49,24 +138,6 @@
ansible.builtin.import_tasks:
file: "{{ filename }}"
- name: Assertions
ansible.builtin.assert:
that:
- install_method in supported_install_methods
- external_url is ansible.builtin.url
fail_msg: What to say if any of the above conditions fail
success_msg: What to say if all of the above conditions succeed
- name: Pretty print information
ansible.builtin.debug:
msg: >-
{{
dict([
[ 'install_method', install_method ],
[ 'install_method in supported_install_methods', install_method in supported_install_methods ],
])
}}
- name: Generate passwords
block:
- name: Randomly
@@ -130,17 +201,27 @@
- name: Manipulate strings
ansible.builtin.set_fact:
string_with_first_letter_to_uppercase: "{{ 'all_lowercase' | capitalize }}"
string_with_something_replaced: "{{ 'dots.to.dashes' | replace('.','-') }}"
split_string: "{{ 'testMe@example.com' | split('@') | first }}"
string_with_pattern_replaced: >-
{{ '*.domain.com...' | regex_replace('*' | regex_escape, 'star') | regex_replace('\.+$', '') }}
- name: Manipulate lists
block:
- name: Add elements to lists
set_fact:
vars:
programming_languages:
- C
- Python
ansible.builtin.set_fact:
programming_languages: "{{ programming_languages + ['Ruby'] }}"
- name: Remove elements from lists
set_fact:
vars:
dbs_list: ['primary', 'sales']
ansible.builtin.set_fact:
list_without_items: "{{ dbs_list | difference(['template0','template1','postgres','rdsadmin']) }}"
- name: Get a random element
set_fact:
ansible.builtin.set_fact:
random_item: "{{ ['a','b','c'] | random }}"
- name: Sort dict elements in list by attribute
tags: order_by
@@ -150,7 +231,7 @@
create_time: '2024-06-25T00:52:55.127000+00:00'
- name: test
create_time: '2024-05-17T01:53:12.103220+00:00'
set_fact:
ansible.builtin.set_fact:
snapshot_latest: "{{ snapshots | sort(attribute='create_time') | last }}"
- name: Give back the first not null value (coalesce-like)
vars:
@@ -159,21 +240,21 @@
- null
- something
- something else
set_fact:
ansible.builtin.set_fact:
first_non_null_value: "{{ list_with_null_values | select | first }}"
- name: Get values for a specific attribute in a list of dictionaries
set_fact:
ansible.builtin.set_fact:
vpc_security_group_ids: >-
{{ instance_information.vpc_security_groups | map(attribute='vpc_security_group_id') }}
volume_ids: "{{ instances_information.instances[0].block_device_mappings | map(attribute='ebs.volume_id') }}"
- name: Return only elements with specific attributes matching a filter
set_fact:
available_rds_snapshots: snapshots_list | selectattr("status", "equalto", "available")
mounts_with_path: ansible_facts.mounts | selectattr('mount', 'in', path)
ansible.builtin.set_fact:
available_rds_snapshots: "{{ snapshots_list | selectattr('status', 'equalto', 'available') }}"
mounts_with_path: "{{ ansible_facts.mounts | selectattr('mount', 'in', path) }}"
- name: Return all elements *but* the ones with specific attributes matching a filter
set_fact:
available_rds_snapshots: snapshots_list | rejectattr("status", "equalto", "creating")
mounts_without_path: ansible_facts.mounts | rejectattr('mount', 'in', path)
ansible.builtin.set_fact:
available_rds_snapshots: "{{ snapshots_list | rejectattr('status', 'equalto', 'creating') }}"
mounts_without_path: "{{ ansible_facts.mounts | rejectattr('mount', 'in', path) }}"
- name: Remove lines about RDS protected users and permissions from a dump file
# remove empty lines
# remove comments
@@ -198,15 +279,19 @@
}}
- name: Manipulate dictionaries
vars:
organization:
address: 123 common lane
id: 123abc
block:
- name: Add keys to dictionaries
set_fact:
ansible.builtin.set_fact:
organization: "{{ organization | combine({ 'name': 'ExampleOrg' }) }}"
- name: Sort keys in dictionaries
set_fact:
ansible.builtin.set_fact:
organization: "{{ organization | dictsort }}"
- name: Pretty print dictionaries
set_fact:
ansible.builtin.set_fact:
organization: "{{ organization | to_nice_json }}"
- name: Merge dictionaries
vars:
@@ -218,7 +303,7 @@
z:
- 4
- test
set_fact:
ansible.builtin.set_fact:
merged_dict: "{{ dict1 | ansible.builtin.combine(dict_2, {'z':'new_value','w':[44]}) }}"
recursively_merged_dict: >-
{{ {'rest':'test'} | ansible.builtin.combine({'z':'new_value','w':[44]}, dict_1, dict_2, recursive=true) }}
@@ -234,7 +319,7 @@
})
}}
with_items: "{{ db_extensions_query.results }}"
- name: FIXME
- name: Register the list of extensions per DB as 'db:extensions[]' pairs
vars:
db_extensions:
sales:
@@ -280,16 +365,16 @@
{%- endfor -%}
{{ ns.devices_list }}
- name: "Use the users' home directory for something"
- name: Use the users' home directory for something
block:
- name: Executing commands from specified users
block:
- name: "Get users' homedir back"
- name: Get users' homedir back
become: true
become_user: "{{ item }}"
become_flags: "-iH"
become_flags: -iH
check_mode: false
command: >-
ansible.builtin.command: >-
echo "{{ item }}: $HOME"
changed_when: false
with_items:
@@ -313,13 +398,13 @@
path: "{{ item.value }}/placeholder"
state: touch
with_dict: "{{ users_homedir }}"
- name: "From the system's entries"
- name: From the system's entries
block:
- name: "Get raw information from the system's entries"
- name: Get raw information from the system's entries
ansible.builtin.getent:
database: passwd
key: "{{ item }}"
split: ":"
split: ':'
with_items:
- root
- ec2-user
@@ -363,21 +448,13 @@
&& aws s3 cp "$FILENAME" 's3://backups/prometheus/'
&& rm "$FILENAME"
- name: Debug tasks
debugger: on_failed
ansible.builtin.fail:
msg: Manual, enforced failure
# print all variables at this point => p task_vars
# continue => c
# abort and quit => q
- name: Error handling in blocks
block:
- name: This executes normally
ansible.builtin.debug:
msg: I execute normally
- name: This errors out
ansible.builtin.command: "/bin/false"
ansible.builtin.command: /bin/false
- name: This never executes
ansible.builtin.debug:
msg: I never execute due to the above task failing
@@ -390,12 +467,45 @@
ansible.builtin.debug:
msg: I always execute
- name: Integrate Ansible Vault
tags: ansible_vault
block:
- name: Use encrypted values
ansible.builtin.set_fact:
var_from_encrypted_value:
# password: '1q2w3e4r', plaintext value: 'very secret string'
!vault |
$ANSIBLE_VAULT;1.1;AES256
34646464653830386631363430386432666530356364313532313336373665613038633464376335
3539363530613130623638313063363165386230646566640a313438386133366137383939336637
33333365393337326239336264623462373064383663363234353635316538356461353061646563
3037306464363439340a663430313739393439363936613862316361353330363638323065383063
39613935613035343637336537643266313737666635313730353034373736353736
- name: Use encrypted files
# The 'unvault' filter requires files to exist beforehand, but it is fine for them to be plaintext. \_(-_-)_/
tags: tls_certificate
ansible.builtin.copy:
dest: /etc/haproxy/certificate.pem
content: |
{{ lookup('ansible.builtin.unvault', 'path/to/cert/key.pem') | string | trim }}
{{ lookup('ansible.builtin.unvault', 'path/to/cert/full_chain.pem') | string | trim }}
- name: Save data to encrypted files
# Of fu*king course the 'vault' filter would use the 'filter_default' vault ID by default to encrypt content.
# Set that parameter to '' to *not* specify a vault ID.
vars:
ansible_vault_password: >-
{{ lookup('ansible.builtin.file', [playbook_dir, 'ansible_vault_password_file.txt'] | path_join) }}
ansible.builtin.copy:
dest: path/to/file
decrypt: false # necessary if the file does not exist beforehand
content: "{{ 'some string' | ansible.builtin.vault(ansible_vault_password, vault_id='') }}"
- name: AWS
tags: aws
block:
- name: Get current IP ranges
# too many to be put into security group rules
set_fact:
ansible.builtin.set_fact:
ip_ranges: >-
lookup('url', 'https://ip-ranges.amazonaws.com/ip-ranges.json', split_lines=False)
| from_json
@@ -411,7 +521,7 @@
secret_key: 123456789abcdefghijklmnopqrstuvwxyzABCDE # optional if defined as environment variable
profile: someProfile # optional if defined as environment variable
role_arn: "arn:aws:iam::123456789012:role/someRole"
role_session_name: "someRoleSession"
role_session_name: someRoleSession
register: assumed_role
- name: Use the assumed role to take action
amazon.aws.ec2_tag:
@@ -428,7 +538,7 @@
amazon.aws.ec2_instance_info:
filters:
"tag:Application": K8S
"instance-state-name": ["running"]
instance-state-name: ["running"]
- name: Clone EC2 instances
vars:
source_instance_id: i-0123456789abcdef0
@@ -460,44 +570,44 @@
block:
- name: Create the snapshot
amazon.aws.rds_instance_snapshot:
db_instance_identifier: "db-identifier"
db_snapshot_identifier: "db-identifier-snapshot"
db_instance_identifier: identifier-for-db-instance
db_snapshot_identifier: identifier-for-db-snapshot
register: snapshot_creation
- name: Wait for the snapshot to be in the 'available state'
- name: Wait for the snapshot to be in the 'available' state
when: snapshot_creation.snapshot_create_time is defined
amazon.aws.rds_snapshot_info:
db_snapshot_identifier: "{{ snapshot_creation.db_snapshot_identifier }}"
register: snapshot_check
retries: 3
delay: 120
until: snapshot_check.snapshots | selectattr("status", "equalto", "available") | length > 0
- name: "Dump roles' privileges"
until: snapshot_check.snapshots | selectattr('status', 'equalto', 'available') | length > 0
- name: Dump roles' privileges
block:
- name: Dump to file
environment:
PGPASSWORD: "someRandomString"
PGPASSWORD: someRandomString
vars:
out_file: /tmp/instance-id_roles.sql
ansible.builtin.command: >-
pg_dumpall
--host 'instance-id.c4v563ptr321.eu-west-1.rds.amazonaws.com' --port '5432'
--host 'instance-id.0123456789ab.eu-west-1.rds.amazonaws.com' --port '5432'
--user 'postgres' --database 'postgres' --no-password
--roles-only --no-role-passwords
--file '{{ out_file }}'
changed_when: false
- name: Dump to variable for later use through 'dump_execution.stdout_lines'
environment:
PGPASSWORD: "someRandomString"
PGPASSWORD: someRandomString
ansible.builtin.command: >-
pg_dumpall
-h 'instance-id.c4v563ptr321.eu-west-1.rds.amazonaws.com' -p '5432'
-h 'instance-id.0123456789ab.eu-west-1.rds.amazonaws.com' -p '5432'
-U 'postgres' -l 'postgres' -w
-r --no-role-passwords
changed_when: false
register: dump_execution
- name: Wait for pending changes to be applied
amazon.aws.rds_instance_info:
db_instance_identifier: "{{ db_instance_identifier }}"
db_instance_identifier: identifier-for-db-instance
register: instance_check
retries: 12
delay: 15
@@ -543,3 +653,14 @@
awx.awx.export:
all: true
register: awx_export_output
- name: Let's Encrypt
# The 'acme_certificate' module takes in file paths for the certificate's files; those need either to *not* exist
# beforehand, or their content to be in specific formats.
block:
- name: Revoke test certificates with account key
community.crypto.acme_certificate_revoke:
acme_directory: https://acme-staging-v02.api.letsencrypt.org/directory
acme_version: 2
account_key_src: path/to/acme_account.key.pem
certificate: path/to/certificate.crt.pem

View File

@@ -9,6 +9,7 @@ python -m 'http.server'
python -m 'http.server' '8080' --bind 'localhost' --directory '/files/to/serve' --protocol 'HTTP/1.1' --cgi
# Quick 'n' dirty web server
# pip install --user 'twisted' 'pyopenssl'
# https://twisted.org/
# pip install --user 'twisted[tls]'
twistd -no web
twistd -no web --path '/files/to/serve' --https '8443' --certificate 'server.pem' --privkey 'server.pem'