Compare commits
44 Commits
5fbf645dd9
...
5d99bf51da
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d99bf51da | |||
| 5ff9ca4687 | |||
| d364f82c9f | |||
| ce62e4afa6 | |||
| f2be3f4899 | |||
| fd5f6f5bca | |||
| eb7bb02e86 | |||
| 7f3bb699f9 | |||
| 7d73885162 | |||
| 3be40169b2 | |||
| 08053e6c39 | |||
| 5073008506 | |||
| 0ab26cae67 | |||
| 4920837641 | |||
| 8764bede85 | |||
| c751ced793 | |||
| 03a1a5879e | |||
| 1ecff67cd9 | |||
| 8e9b993f14 | |||
| 659feb3322 | |||
| 00486fbc8d | |||
| f7ba34ec69 | |||
| 5440fd3acb | |||
| c1af7193f7 | |||
| f39bb9c8a3 | |||
| 40fa1312c4 | |||
| 8ba6a236f8 | |||
| 4f9ecc84d3 | |||
| 217ace503f | |||
| a614f4461f | |||
| 4a658857b3 | |||
| 9f85033aff | |||
| 9aac725e88 | |||
| c45946739e | |||
| 4c9a4d480e | |||
| 020fcf2c51 | |||
| 6a2179d7a0 | |||
| 6eaeeb0322 | |||
| f01f1b5431 | |||
| 9c770faa23 | |||
| 7dae1fc086 | |||
| 43cfc07c11 | |||
| 3a558c5bad | |||
| b6b4aad798 |
129
.ansible-lint.yml
Normal file
129
.ansible-lint.yml
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
---
|
||||||
|
# .ansible-lint
|
||||||
|
|
||||||
|
profile: null # min, basic, moderate,safety, shared, production
|
||||||
|
|
||||||
|
# Allows dumping of results in SARIF format
|
||||||
|
# sarif_file: result.sarif
|
||||||
|
|
||||||
|
# exclude_paths included in this file are parsed relative to this file's location
|
||||||
|
# and not relative to the CWD of execution. CLI arguments passed to the --exclude
|
||||||
|
# option are parsed relative to the CWD of execution.
|
||||||
|
exclude_paths:
|
||||||
|
- .cache/ # implicit unless exclude_paths is defined in config
|
||||||
|
- test/fixtures/formatting-before/
|
||||||
|
- test/fixtures/formatting-prettier/
|
||||||
|
# quiet: true
|
||||||
|
# strict: true
|
||||||
|
# verbosity: 1
|
||||||
|
|
||||||
|
# Mock modules or roles in order to pass ansible-playbook --syntax-check
|
||||||
|
mock_modules:
|
||||||
|
- zuul_return
|
||||||
|
# note the foo.bar is invalid as being neither a module or a collection
|
||||||
|
- fake_namespace.fake_collection.fake_module
|
||||||
|
- fake_namespace.fake_collection.fake_module.fake_submodule
|
||||||
|
mock_roles:
|
||||||
|
- mocked_role
|
||||||
|
- author.role_name # old standalone galaxy role
|
||||||
|
- fake_namespace.fake_collection.fake_role # role within a collection
|
||||||
|
|
||||||
|
# Enable checking of loop variable prefixes in roles
|
||||||
|
loop_var_prefix: "^(__|{role}_)"
|
||||||
|
|
||||||
|
# Enforce variable names to follow pattern below, in addition to Ansible own
|
||||||
|
# requirements, like avoiding python identifiers. To disable add `var-naming`
|
||||||
|
# to skip_list.
|
||||||
|
var_naming_pattern: "^[a-z_][a-z0-9_]*$"
|
||||||
|
|
||||||
|
use_default_rules: true
|
||||||
|
# Load custom rules from this specific folder
|
||||||
|
# rulesdir:
|
||||||
|
# - ./rule/directory/
|
||||||
|
|
||||||
|
# Ansible-lint is able to recognize and load skip rules stored inside
|
||||||
|
# `.ansible-lint-ignore` (or `.config/ansible-lint-ignore.txt`) files.
|
||||||
|
# To skip a rule just enter filename and tag, like "playbook.yml package-latest"
|
||||||
|
# on a new line.
|
||||||
|
# Optionally you can add comments after the tag, prefixed by "#". We discourage
|
||||||
|
# the use of skip_list below because that will hide violations from the output.
|
||||||
|
# When putting ignores inside the ignore file, they are marked as ignored, but
|
||||||
|
# still visible, making it easier to address later.
|
||||||
|
skip_list:
|
||||||
|
- skip_this_tag
|
||||||
|
|
||||||
|
# Ansible-lint does not automatically load rules that have the 'opt-in' tag.
|
||||||
|
# You must enable opt-in rules by listing each rule 'id' below.
|
||||||
|
enable_list:
|
||||||
|
- args
|
||||||
|
- empty-string-compare # opt-in
|
||||||
|
- no-log-password # opt-in
|
||||||
|
- no-same-owner # opt-in
|
||||||
|
- name[prefix] # opt-in
|
||||||
|
- galaxy-version-incorrect # opt-in
|
||||||
|
# add yaml here if you want to avoid ignoring yaml checks when yamllint
|
||||||
|
# library is missing. Normally its absence just skips using that rule.
|
||||||
|
- yaml
|
||||||
|
# Report only a subset of tags and fully ignore any others
|
||||||
|
# tags:
|
||||||
|
# - jinja[spacing]
|
||||||
|
|
||||||
|
# Ansible-lint does not fail on warnings from the rules or tags listed below
|
||||||
|
warn_list:
|
||||||
|
- skip_this_tag
|
||||||
|
- experimental # experimental is included in the implicit list
|
||||||
|
# - role-name
|
||||||
|
# - yaml[document-start] # you can also use sub-rule matches
|
||||||
|
|
||||||
|
# Some rules can transform files to fix (or make it easier to fix) identified
|
||||||
|
# errors. `ansible-lint --fix` will reformat YAML files and run these transforms.
|
||||||
|
# By default it will run all transforms (effectively `write_list: ["all"]`).
|
||||||
|
# You can disable running transforms by setting `write_list: ["none"]`.
|
||||||
|
# Or only enable a subset of rule transforms by listing rules/tags here.
|
||||||
|
# write_list:
|
||||||
|
# - all
|
||||||
|
|
||||||
|
# Offline mode disables installation of requirements.yml and schema refreshing
|
||||||
|
offline: true
|
||||||
|
|
||||||
|
# Define required Ansible's variables to satisfy syntax check
|
||||||
|
extra_vars:
|
||||||
|
foo: bar
|
||||||
|
multiline_string_variable: |
|
||||||
|
line1
|
||||||
|
line2
|
||||||
|
complex_variable: ":{;\t$()"
|
||||||
|
|
||||||
|
# Uncomment to enforce action validation with tasks, usually is not
|
||||||
|
# needed as Ansible syntax check also covers it.
|
||||||
|
# skip_action_validation: false
|
||||||
|
|
||||||
|
# List of additional kind:pattern to be added at the top of the default
|
||||||
|
# match list, first match determines the file kind.
|
||||||
|
kinds:
|
||||||
|
# - playbook: "**/examples/*.{yml,yaml}"
|
||||||
|
# - galaxy: "**/folder/galaxy.yml"
|
||||||
|
# - tasks: "**/tasks/*.yml"
|
||||||
|
# - vars: "**/vars/*.yml"
|
||||||
|
# - meta: "**/meta/main.yml"
|
||||||
|
- yaml: "**/*.yaml-too"
|
||||||
|
|
||||||
|
# List of additional collections to allow in only-builtins rule.
|
||||||
|
# only_builtins_allow_collections:
|
||||||
|
# - example_ns.example_collection
|
||||||
|
|
||||||
|
# List of additions modules to allow in only-builtins rule.
|
||||||
|
# only_builtins_allow_modules:
|
||||||
|
# - example_module
|
||||||
|
|
||||||
|
# Allow setting custom prefix for name[prefix] rule
|
||||||
|
task_name_prefix: "{stem} | "
|
||||||
|
|
||||||
|
# Complexity related settings
|
||||||
|
|
||||||
|
# Limit the depth of the nested blocks:
|
||||||
|
# max_block_depth: 20
|
||||||
|
|
||||||
|
# Also recognize these versions of Ansible as supported:
|
||||||
|
# supported_ansible_also:
|
||||||
|
# - "2.18"
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# This is a mocked Ansible module generated by ansible-lint
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
module: fake_namespace.fake_collection.fake_module
|
||||||
|
|
||||||
|
short_description: Mocked
|
||||||
|
version_added: "1.0.0"
|
||||||
|
description: Mocked
|
||||||
|
|
||||||
|
author:
|
||||||
|
- ansible-lint (@nobody)
|
||||||
|
'''
|
||||||
|
EXAMPLES = '''mocked'''
|
||||||
|
RETURN = '''mocked'''
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
result = dict(
|
||||||
|
changed=False,
|
||||||
|
original_message='',
|
||||||
|
message='')
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# This is a mocked Ansible module generated by ansible-lint
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
module: fake_namespace.fake_collection.fake_module.fake_submodule
|
||||||
|
|
||||||
|
short_description: Mocked
|
||||||
|
version_added: "1.0.0"
|
||||||
|
description: Mocked
|
||||||
|
|
||||||
|
author:
|
||||||
|
- ansible-lint (@nobody)
|
||||||
|
'''
|
||||||
|
EXAMPLES = '''mocked'''
|
||||||
|
RETURN = '''mocked'''
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
result = dict(
|
||||||
|
changed=False,
|
||||||
|
original_message='',
|
||||||
|
message='')
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
32
.ansible/modules/zuul_return.py
Normal file
32
.ansible/modules/zuul_return.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# This is a mocked Ansible module generated by ansible-lint
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
module: zuul_return
|
||||||
|
|
||||||
|
short_description: Mocked
|
||||||
|
version_added: "1.0.0"
|
||||||
|
description: Mocked
|
||||||
|
|
||||||
|
author:
|
||||||
|
- ansible-lint (@nobody)
|
||||||
|
'''
|
||||||
|
EXAMPLES = '''mocked'''
|
||||||
|
RETURN = '''mocked'''
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
result = dict(
|
||||||
|
changed=False,
|
||||||
|
original_message='',
|
||||||
|
message='')
|
||||||
|
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec=dict(),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,4 +1,11 @@
|
|||||||
# Ansible Tower ignore list
|
# Ansible Tower ignore list
|
||||||
|
/hosts
|
||||||
|
/hosts.test.yml
|
||||||
|
/hosts.yml
|
||||||
|
/hosts.yaml
|
||||||
|
/hosts.json
|
||||||
|
*.bak
|
||||||
|
/init@homeserver.yml
|
||||||
|
|
||||||
# Ansible runtime and backups
|
# Ansible runtime and backups
|
||||||
*.original
|
*.original
|
||||||
@@ -11,6 +18,8 @@
|
|||||||
.galcache/
|
.galcache/
|
||||||
/collections/ansible_collections/
|
/collections/ansible_collections/
|
||||||
/.devcontainer/
|
/.devcontainer/
|
||||||
|
.lock
|
||||||
|
/.cache/
|
||||||
|
|
||||||
# Try tyo avoid any plain-text passwords
|
# Try tyo avoid any plain-text passwords
|
||||||
*pwd*
|
*pwd*
|
||||||
|
|||||||
10
ansible.cfg
10
ansible.cfg
@@ -96,6 +96,7 @@ action_plugins=plugins/action:~/.ansible/plugins/action:/usr/share/ansible/plugi
|
|||||||
# (pathspec) Colon-separated paths in which Ansible will search for Cache Plugins.
|
# (pathspec) Colon-separated paths in which Ansible will search for Cache Plugins.
|
||||||
cache_plugins=plugins/cache:~/.ansible/plugins/cache:/usr/share/ansible/plugins/cache
|
cache_plugins=plugins/cache:~/.ansible/plugins/cache:/usr/share/ansible/plugins/cache
|
||||||
|
|
||||||
|
callback_result_format=yaml
|
||||||
# (pathspec) Colon-separated paths in which Ansible will search for Callback Plugins.
|
# (pathspec) Colon-separated paths in which Ansible will search for Callback Plugins.
|
||||||
callback_plugins=plugins/callback:~/.ansible/plugins/callback:/usr/share/ansible/plugins/callback
|
callback_plugins=plugins/callback:~/.ansible/plugins/callback:/usr/share/ansible/plugins/callback
|
||||||
|
|
||||||
@@ -138,7 +139,7 @@ gathering=smart
|
|||||||
;hash_behaviour=replace
|
;hash_behaviour=replace
|
||||||
|
|
||||||
# (pathlist) Comma-separated list of Ansible inventory sources
|
# (pathlist) Comma-separated list of Ansible inventory sources
|
||||||
inventory=['.','inv','/etc/ansible/hosts']
|
inventory=['hosts','hosts.yml','hosts.yaml','hosts.json','/etc/ansible/hosts','/etc/ansible/hosts.yml','/etc/ansible/hosts.yaml','/etc/ansible/hosts.json']
|
||||||
|
|
||||||
# (pathspec) Colon-separated paths in which Ansible will search for HttpApi Plugins.
|
# (pathspec) Colon-separated paths in which Ansible will search for HttpApi Plugins.
|
||||||
httpapi_plugins=plugins/httpapi:~/.ansible/plugins/httpapi:/usr/share/ansible/plugins/httpapi
|
httpapi_plugins=plugins/httpapi:~/.ansible/plugins/httpapi:/usr/share/ansible/plugins/httpapi
|
||||||
@@ -233,7 +234,7 @@ roles_path=roles:~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
|
|||||||
# (string) Set the main callback used to display Ansible output. You can only have one at a time.
|
# (string) Set the main callback used to display Ansible output. You can only have one at a time.
|
||||||
# You can have many other callbacks, but just one can be in charge of stdout.
|
# You can have many other callbacks, but just one can be in charge of stdout.
|
||||||
# See :ref:`callback_plugins` for a list of available options.
|
# See :ref:`callback_plugins` for a list of available options.
|
||||||
stdout_callback=yaml
|
;stdout_callback=yaml
|
||||||
|
|
||||||
# (string) Set the default strategy used for plays.
|
# (string) Set the default strategy used for plays.
|
||||||
;strategy=linear
|
;strategy=linear
|
||||||
@@ -318,7 +319,7 @@ doc_fragment_plugins=plugins/doc_fragments:~/.ansible/plugins/doc_fragments:/usr
|
|||||||
# (boolean) Whether or not to enable the task debugger, this previously was done as a strategy plugin.
|
# (boolean) Whether or not to enable the task debugger, this previously was done as a strategy plugin.
|
||||||
# Now all strategy plugins can inherit this behavior. The debugger defaults to activating when
|
# Now all strategy plugins can inherit this behavior. The debugger defaults to activating when
|
||||||
# a task is failed on unreachable. Use the debugger keyword for more flexibility.
|
# a task is failed on unreachable. Use the debugger keyword for more flexibility.
|
||||||
;enable_task_debugger=False
|
enable_task_debugger=True
|
||||||
|
|
||||||
# (boolean) Toggle to allow missing handlers to become a warning instead of an error when notifying.
|
# (boolean) Toggle to allow missing handlers to become a warning instead of an error when notifying.
|
||||||
;error_on_missing_handler=True
|
;error_on_missing_handler=True
|
||||||
@@ -331,6 +332,7 @@ doc_fragment_plugins=plugins/doc_fragments:~/.ansible/plugins/doc_fragments:/usr
|
|||||||
# (boolean) Set this to "False" if you want to avoid host key checking by the underlying connection plugin Ansible uses to connect to the host.
|
# (boolean) Set this to "False" if you want to avoid host key checking by the underlying connection plugin Ansible uses to connect to the host.
|
||||||
# Please read the documentation of the specific connection plugin used for details.
|
# Please read the documentation of the specific connection plugin used for details.
|
||||||
;host_key_checking=True
|
;host_key_checking=True
|
||||||
|
host_key_checking=False
|
||||||
|
|
||||||
# (boolean) Facts are available inside the `ansible_facts` variable, this setting also pushes them as their own vars in the main namespace.
|
# (boolean) Facts are available inside the `ansible_facts` variable, this setting also pushes them as their own vars in the main namespace.
|
||||||
# Unlike inside the `ansible_facts` dictionary where the prefix `ansible_` is removed from fact names, these will have the exact names that are returned by the module.
|
# Unlike inside the `ansible_facts` dictionary where the prefix `ansible_` is removed from fact names, these will have the exact names that are returned by the module.
|
||||||
@@ -663,7 +665,7 @@ token_path=.gal_token
|
|||||||
;any_unparsed_is_failed=False
|
;any_unparsed_is_failed=False
|
||||||
|
|
||||||
# (list) List of enabled inventory plugins, it also determines the order in which they are used.
|
# (list) List of enabled inventory plugins, it also determines the order in which they are used.
|
||||||
;enable_plugins=host_list, script, auto, yaml, ini, toml
|
enable_plugins=host_list, script, auto, yaml, ini, toml
|
||||||
|
|
||||||
# (bool) Controls if ansible-inventory will accurately reflect Ansible's view into inventory or its optimized for exporting.
|
# (bool) Controls if ansible-inventory will accurately reflect Ansible's view into inventory or its optimized for exporting.
|
||||||
;export=False
|
;export=False
|
||||||
|
|||||||
3
dry_run.sh
Executable file
3
dry_run.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ansible-playbook --ask-pass --ask-become-pass -i hosts.yml init@homeserver.yml --check
|
||||||
@@ -13,26 +13,26 @@ instance: armitage
|
|||||||
# operating_system: "tftp://hikiki.local:69/debian.iso"
|
# operating_system: "tftp://hikiki.local:69/debian.iso"
|
||||||
operating_system: ~
|
operating_system: ~
|
||||||
# <list[<str>]> of control node or local SSH key basenames
|
# <list[<str>]> of control node or local SSH key basenames
|
||||||
keys:
|
ssh_keys:
|
||||||
- id_ed25519_localhost
|
- id_ed25519_localhost
|
||||||
# <list<dict>> list of administrative users (in Linux, users that can use "sudo")
|
# <list<dict>> list of administrative users (in Linux, users that can use "sudo")
|
||||||
admins:
|
admins:
|
||||||
- username: admin # <str> arbitrary valid user name
|
- username: admin # <str> arbitrary valid user name
|
||||||
services: ~ # <list[<str>]> if linux system user, assocated servce
|
services: ~ # <list[<str>]> if linux system user, assocated servce
|
||||||
# <list[<str>]> list of control node or local SSH key basenames for this user
|
# <list[<str>]> list of control node or local SSH key basenames for this user
|
||||||
keys: "{{ keys }}"
|
ssh_keys: "{{ keys }}"
|
||||||
# <str<vault?>> hashed (and maybe salted) password
|
# <str<vault?>> hashed (and maybe salted) password
|
||||||
password: !vault |
|
password: !vault |
|
||||||
$ANSIBLE_VAULT;1.1;AES256
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
34396235306630656138303939346638343135623430353666326462663131613130643061366435
|
33663131343861303735643439393165356231366338346538333537643464343761373139303364
|
||||||
6563616331656566626263633966633764386564383961640a656466323835616263653531323861
|
6630303563346437373161626662313432306138353132350a353334356139376662333562353834
|
||||||
65376663363934653163313666303166376262623334343034626535356431636662366261333061
|
36326461613664616565373835303636636533616462303732633461343130346134366662373566
|
||||||
3866656638623631660a386666383136396238633365333465333766383766303631663336326264
|
6431623034653363310a303665636366353535313436666532623737373930356364616339313633
|
||||||
35663339663062333162643039663430363265393163303839356664343633373630303462393735
|
34663839656637373031393031656332393761623161643730326563323863363461333864353338
|
||||||
37316262383335323837646265336139373238623735383134623361363136663436393162666336
|
30633964353339323465643064636538346464343035626461333366303835333039653661383030
|
||||||
62353462323534316531313533636461353139326466646662356233373130616633633262616539
|
62656663336536373262623062633563646434646431303137306438633937323764633334396539
|
||||||
37306332666338363231383537343832396432666134663462633336646330646332306634356636
|
64353734613662663063343966356562326661626436663430623430663766343030646333306634
|
||||||
36626166386634653537613334616538313266323866303738316430666131646333
|
32353839313235313339353431323837356537336231366564313431313462613333
|
||||||
pkgs:
|
pkgs:
|
||||||
# <dict[<str>:<dict>]> representing package groups installed by package manager via repositories
|
# <dict[<str>:<dict>]> representing package groups installed by package manager via repositories
|
||||||
mngr:
|
mngr:
|
||||||
@@ -207,6 +207,18 @@ pkgs:
|
|||||||
key_path: ~
|
key_path: ~
|
||||||
src_entry: ~
|
src_entry: ~
|
||||||
src_path: ~
|
src_path: ~
|
||||||
|
- name: python3-venv
|
||||||
|
uri: ~
|
||||||
|
key: ~
|
||||||
|
key_path: ~
|
||||||
|
src_entry: ~
|
||||||
|
src_path: ~
|
||||||
|
- name: python3-pip
|
||||||
|
uri: ~
|
||||||
|
key: ~
|
||||||
|
key_path: ~
|
||||||
|
src_entry: ~
|
||||||
|
src_path: ~
|
||||||
- name: golang
|
- name: golang
|
||||||
uri: ~
|
uri: ~
|
||||||
key: ~
|
key: ~
|
||||||
@@ -238,6 +250,18 @@ pkgs:
|
|||||||
src_entry: ~
|
src_entry: ~
|
||||||
src_path: ~
|
src_path: ~
|
||||||
handler: ~
|
handler: ~
|
||||||
|
- name: avahi-daemon
|
||||||
|
uri: ~
|
||||||
|
key: ~
|
||||||
|
key_path: ~
|
||||||
|
src_entry: ~
|
||||||
|
src_path: ~
|
||||||
|
- name: avahi-utils
|
||||||
|
uri: ~
|
||||||
|
key: ~
|
||||||
|
key_path: ~
|
||||||
|
src_entry: ~
|
||||||
|
src_path: ~
|
||||||
# <dict[<str>:<dict>]> representing package groups installed by shell scripts
|
# <dict[<str>:<dict>]> representing package groups installed by shell scripts
|
||||||
script:
|
script:
|
||||||
# <list[<dict>]> representing user-level or supplemental shell script installations
|
# <list[<dict>]> representing user-level or supplemental shell script installations
|
||||||
@@ -254,6 +278,10 @@ pkgs:
|
|||||||
src: "https://install.julialang.org"
|
src: "https://install.julialang.org"
|
||||||
pre: ~
|
pre: ~
|
||||||
post: ~
|
post: ~
|
||||||
|
- name: uv
|
||||||
|
src: "https://astral.sh/uv/install.sh"
|
||||||
|
pre: ~
|
||||||
|
post: ~
|
||||||
# <dict[<str>:<dict>]> representing package groups installed from source archives
|
# <dict[<str>:<dict>]> representing package groups installed from source archives
|
||||||
archive:
|
archive:
|
||||||
# <list[<dict>]> representing user-level or supplemental source archives
|
# <list[<dict>]> representing user-level or supplemental source archives
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ instance: ""
|
|||||||
# Example-- operating_system: "tftp://hikiki.local:69/debian.iso"
|
# Example-- operating_system: "tftp://hikiki.local:69/debian.iso"
|
||||||
operating_system: ~
|
operating_system: ~
|
||||||
# <list[<str>]> of control node or local SSH key basenames
|
# <list[<str>]> of control node or local SSH key basenames
|
||||||
keys: []
|
ssh_keys: []
|
||||||
# <dict[<str>:<dict>]> package groups
|
# <dict[<str>:<dict>]> package groups
|
||||||
pkgs:
|
pkgs:
|
||||||
# <dict[<str>:<dict>]> representing package groups installed by package manager via repositories
|
# <dict[<str>:<dict>]> representing package groups installed by package manager via repositories
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ origin: us-east
|
|||||||
# <str<enum>> representing Linux distro or OS image available in VPS service to be used for VPS
|
# <str<enum>> representing Linux distro or OS image available in VPS service to be used for VPS
|
||||||
operating_system: linode/debian13
|
operating_system: linode/debian13
|
||||||
# <list[<str>]> list of control node or local SSH key basenames for root user
|
# <list[<str>]> list of control node or local SSH key basenames for root user
|
||||||
keys:
|
ssh_keys:
|
||||||
- id_ecdsa-sha2_sukaato_miniyubikey
|
- id_ecdsa-sha2_sukaato_miniyubikey
|
||||||
- id_ecdsa-sha2_sukaato_yubikey
|
- id_ecdsa-sha2_sukaato_yubikey
|
||||||
# <list<dict>> list of administrative users (in Linux, users that can use "sudo")
|
# <list<dict>> list of administrative users (in Linux, users that can use "sudo")
|
||||||
@@ -32,7 +32,7 @@ admins:
|
|||||||
- username: senpai # <str> arbitrary valid user name
|
- username: senpai # <str> arbitrary valid user name
|
||||||
services: ~ # <list[<str>]> if linux system user, assocated servce
|
services: ~ # <list[<str>]> if linux system user, assocated servce
|
||||||
# <list[<str>]> list of control node or local SSH key basenames for this user
|
# <list[<str>]> list of control node or local SSH key basenames for this user
|
||||||
keys:
|
ssh_keys:
|
||||||
- id_ed25519_sukaato_yubikey
|
- id_ed25519_sukaato_yubikey
|
||||||
- id_ed25519_sukaato_miniyubikey
|
- id_ed25519_sukaato_miniyubikey
|
||||||
# <str<vault?>> hashed (and maybe salted) password
|
# <str<vault?>> hashed (and maybe salted) password
|
||||||
@@ -222,6 +222,18 @@ pkgs:
|
|||||||
key_path: ~
|
key_path: ~
|
||||||
src_entry: ~
|
src_entry: ~
|
||||||
src_path: ~
|
src_path: ~
|
||||||
|
- name: python3-venv
|
||||||
|
uri: ~
|
||||||
|
key: ~
|
||||||
|
key_path: ~
|
||||||
|
src_entry: ~
|
||||||
|
src_path: ~
|
||||||
|
- name: python3-pip
|
||||||
|
uri: ~
|
||||||
|
key: ~
|
||||||
|
key_path: ~
|
||||||
|
src_entry: ~
|
||||||
|
src_path: ~
|
||||||
- name: golang
|
- name: golang
|
||||||
uri: ~
|
uri: ~
|
||||||
key: ~
|
key: ~
|
||||||
@@ -269,6 +281,10 @@ pkgs:
|
|||||||
src: "https://install.julialang.org"
|
src: "https://install.julialang.org"
|
||||||
pre: ~
|
pre: ~
|
||||||
post: ~
|
post: ~
|
||||||
|
- name: uv
|
||||||
|
src: "https://astral.sh/uv/install.sh"
|
||||||
|
pre: ~
|
||||||
|
post: ~
|
||||||
# <dict[<str>:<dict>]> representing package groups installed from source archives
|
# <dict[<str>:<dict>]> representing package groups installed from source archives
|
||||||
archive:
|
archive:
|
||||||
# <list[<dict>]> representing user-level or supplemental source archives
|
# <list[<dict>]> representing user-level or supplemental source archives
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ origin: ""
|
|||||||
# <str<enum>> representing Linux distro or OS image available in VPS service to be used for VPS
|
# <str<enum>> representing Linux distro or OS image available in VPS service to be used for VPS
|
||||||
operating_system: ~
|
operating_system: ~
|
||||||
# <list[<str>]> of control node or local SSH key basenames
|
# <list[<str>]> of control node or local SSH key basenames
|
||||||
keys: []
|
ssh_keys: []
|
||||||
# <dict[<str>:<dict>]> package groups
|
# <dict[<str>:<dict>]> package groups
|
||||||
pkgs:
|
pkgs:
|
||||||
# <dict[<str>:<dict>]> representing package groups installed by package manager via repositories
|
# <dict[<str>:<dict>]> representing package groups installed by package manager via repositories
|
||||||
|
|||||||
11
hosts.yml.example
Normal file
11
hosts.yml.example
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# @TODO use hosts and host groupings that refer or point to VM or containerized servers for testing
|
||||||
|
ungrouped:
|
||||||
|
hosts: ~
|
||||||
|
sukaato:
|
||||||
|
hosts: ~
|
||||||
|
armitage:
|
||||||
|
hosts: ~
|
||||||
|
vps:
|
||||||
|
children: ~
|
||||||
|
homeserver:
|
||||||
|
children: ~
|
||||||
28
init@homeserver.yml.example
Normal file
28
init@homeserver.yml.example
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# @NOTE run 'ansible-playbook' command on this using 'sudo'
|
||||||
|
- name: Initialize homeserver
|
||||||
|
hosts: armitage
|
||||||
|
remote_user: root
|
||||||
|
vars:
|
||||||
|
harden: true
|
||||||
|
local_facts:
|
||||||
|
user_dir: ~
|
||||||
|
user_id: ~
|
||||||
|
tasks:
|
||||||
|
- name: Hardening SSH server
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: init-server # required. The name of the role to be executed.
|
||||||
|
# apply: # not required. Accepts a hash of task keywords (e.g. C(tags), C(become)) that will be applied to all tasks within the included role.
|
||||||
|
tasks_from: harden # not required. File to load from a role's C(tasks/) directory.
|
||||||
|
# vars_from: main # not required. File to load from a role's C(vars/) directory.
|
||||||
|
# defaults_from: main # not required. File to load from a role's C(defaults/) directory.
|
||||||
|
# allow_duplicates: True # not required. Overrides the role's metadata setting to allow using a role more than once with the same parameters.
|
||||||
|
# handlers_from: main # not required. File to load from a role's C(handlers/) directory.
|
||||||
|
- name: Initializing groups and users
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: init-server # required. The name of the role to be executed.
|
||||||
|
# apply: # not required. Accepts a hash of task keywords (e.g. C(tags), C(become)) that will be applied to all tasks within the included role.
|
||||||
|
tasks_from: ssh-users # not required. File to load from a role's C(tasks/) directory.
|
||||||
|
vars_from: main # not required. File to load from a role's C(vars/) directory.
|
||||||
|
defaults_from: main # not required. File to load from a role's C(defaults/) directory.
|
||||||
|
# allow_duplicates: True # not required. Overrides the role's metadata setting to allow using a role more than once with the same parameters.
|
||||||
|
# handlers_from: main # not required. File to load from a role's C(handlers/) directory.
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
ansible==13.7.0
|
ansible==13.7.0
|
||||||
|
ansible-builder==3.1.1
|
||||||
ansible-compat==26.3.0
|
ansible-compat==26.3.0
|
||||||
ansible-core==2.20.6
|
ansible-core==2.20.6
|
||||||
ansible-lint==26.4.0
|
ansible-lint==26.4.0
|
||||||
|
ansible-navigator==26.4.0
|
||||||
|
ansible-runner==2.4.3
|
||||||
ansible-specdoc==0.0.20
|
ansible-specdoc==0.0.20
|
||||||
appdirs==1.4.4
|
appdirs==1.4.4
|
||||||
attrs==26.1.0
|
attrs==26.1.0
|
||||||
baron==0.10.1
|
baron==0.10.1
|
||||||
|
bindep==2.14.0
|
||||||
black==26.5.1
|
black==26.5.1
|
||||||
bracex==2.6
|
bracex==2.6
|
||||||
certifi==2026.5.20
|
certifi==2026.5.20
|
||||||
@@ -13,29 +17,36 @@ cffi==2.0.0
|
|||||||
charset-normalizer==3.4.7
|
charset-normalizer==3.4.7
|
||||||
click==8.4.1
|
click==8.4.1
|
||||||
cryptography==48.0.0
|
cryptography==48.0.0
|
||||||
Deprecated==1.3.1
|
deprecated==1.3.1
|
||||||
distro==1.9.0
|
distro==1.9.0
|
||||||
enrich==1.2.7
|
enrich==1.2.7
|
||||||
filelock==3.29.0
|
filelock==3.29.0
|
||||||
idna==3.16
|
idna==3.16
|
||||||
Jinja2==3.1.6
|
jinja2==3.1.6
|
||||||
jsonschema==4.26.0
|
jsonschema==4.26.0
|
||||||
jsonschema-specifications==2025.9.1
|
jsonschema-specifications==2025.9.1
|
||||||
linode_api4==5.44.0
|
linode-api4==5.44.0
|
||||||
|
lockfile==0.12.2
|
||||||
markdown-it-py==4.2.0
|
markdown-it-py==4.2.0
|
||||||
MarkupSafe==3.0.3
|
markupsafe==3.0.3
|
||||||
mdurl==0.1.2
|
mdurl==0.1.2
|
||||||
molecule==26.4.0
|
molecule==26.4.0
|
||||||
mypy_extensions==1.1.0
|
mypy-extensions==1.1.0
|
||||||
|
onigurumacffi==1.5.0
|
||||||
packaging==26.2
|
packaging==26.2
|
||||||
|
parsley==1.3
|
||||||
pathspec==1.0.4
|
pathspec==1.0.4
|
||||||
|
pbr==7.0.3
|
||||||
|
pexpect==4.9.0
|
||||||
platformdirs==4.9.6
|
platformdirs==4.9.6
|
||||||
pluggy==1.6.0
|
pluggy==1.6.0
|
||||||
polling==0.3.2
|
polling==0.3.2
|
||||||
|
ptyprocess==0.7.0
|
||||||
pycparser==3.0
|
pycparser==3.0
|
||||||
Pygments==2.20.0
|
pygments==2.20.0
|
||||||
|
python-daemon==3.1.2
|
||||||
pytokens==0.4.1
|
pytokens==0.4.1
|
||||||
PyYAML==6.0.3
|
pyyaml==6.0.3
|
||||||
redbaron==0.9.2
|
redbaron==0.9.2
|
||||||
referencing==0.37.0
|
referencing==0.37.0
|
||||||
requests==2.34.2
|
requests==2.34.2
|
||||||
@@ -43,9 +54,11 @@ resolvelib==1.2.1
|
|||||||
rich==15.0.0
|
rich==15.0.0
|
||||||
rpds-py==0.30.0
|
rpds-py==0.30.0
|
||||||
rply==0.7.8
|
rply==0.7.8
|
||||||
ruamel.yaml==0.19.1
|
ruamel-yaml==0.19.1
|
||||||
ruamel.yaml.clib==0.2.15
|
ruamel-yaml-clib==0.2.15
|
||||||
|
setuptools==82.0.1
|
||||||
subprocess-tee==0.4.2
|
subprocess-tee==0.4.2
|
||||||
|
tzdata==2026.2
|
||||||
urllib3==2.7.0
|
urllib3==2.7.0
|
||||||
wcmatch==10.1
|
wcmatch==10.1
|
||||||
wrapt==2.2.1
|
wrapt==2.2.1
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
|
#SPDX-License-Identifier: MIT-0
|
||||||
|
---
|
||||||
|
# defaults file for roles/init-vps
|
||||||
# <str<bool>> whether to harden managed node's SSH service
|
# <str<bool>> whether to harden managed node's SSH service
|
||||||
harden: true
|
harden: true
|
||||||
@@ -1,54 +1,7 @@
|
|||||||
# SPDX-License-Identifier: MIT-0
|
# SPDX-License-Identifier: MIT-0
|
||||||
---
|
---
|
||||||
# handlers file for roles/init-vps
|
# handlers file for roles/init-vps
|
||||||
- name: Executing relevant files for software installation from git repository
|
- name: Setting up Quartz
|
||||||
block:
|
ansible.builtin.include_tasks:
|
||||||
- name: Finalizing quartz installation
|
file: tasks/contingent/pkg/quartz.yml
|
||||||
listen: quartz
|
listen: quartz
|
||||||
block:
|
|
||||||
- name: Installing NodeJS dependencies of quartz software
|
|
||||||
community.general.npm:
|
|
||||||
executable: "{{ ansible_facts['user_dir'] }}/.nvm/versions/node/v24.11.1/lib/node_modules/npm"
|
|
||||||
path: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
|
|
||||||
state: latest
|
|
||||||
- name: Configuring quartz software
|
|
||||||
block:
|
|
||||||
- name: Initializing quartz website
|
|
||||||
ansible.builtin.command:
|
|
||||||
chdir: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
|
|
||||||
cmd: npx quartz create
|
|
||||||
register: stdout
|
|
||||||
changed_when: stdout.rc == 0
|
|
||||||
- name: Installing quartz plugins referenced in website template
|
|
||||||
ansible.builtin.command:
|
|
||||||
chdir: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
|
|
||||||
cmd: npx quartz plugin install --from-config
|
|
||||||
register: stdout
|
|
||||||
changed_when: stdout.rc == 0
|
|
||||||
# - name: Starting quartz site web server
|
|
||||||
# ansible.builtin.command:
|
|
||||||
# chdir: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
|
|
||||||
# cmd: npx quartz build --serve
|
|
||||||
# register: stdout
|
|
||||||
# changed_when: stdout
|
|
||||||
- name: Committing requisite actions for building software from source archives
|
|
||||||
block:
|
|
||||||
- name: Finalizing building of Surge
|
|
||||||
listen: surge
|
|
||||||
block:
|
|
||||||
- name: Hardlinking Surge executable
|
|
||||||
ansible.builtin.file:
|
|
||||||
src: "{{ ansible_facts['user_dir'] }}/downloads/archives/released/surge/surge"
|
|
||||||
dest: "{{ ansible_facts['user_dir'] }}/.local/bin/surge"
|
|
||||||
state: hard
|
|
||||||
mode: "755"
|
|
||||||
- name: Copying Surge executable
|
|
||||||
become: true
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: "{{ ansible_facts['user_dir'] }}/downloads/archives/released/surge/surge"
|
|
||||||
dest: /usr/bin/surge
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "755"
|
|
||||||
force: true
|
|
||||||
backup: false
|
|
||||||
|
|||||||
26
roles/init-server/tasks/contingent/pkg/quartz.yml
Normal file
26
roles/init-server/tasks/contingent/pkg/quartz.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
- name: Installing NodeJS dependencies of quartz software
|
||||||
|
community.general.npm:
|
||||||
|
executable: "{{ ansible_facts['user_dir'] }}/.nvm/versions/node/v24.11.1/lib/node_modules/npm"
|
||||||
|
path: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
|
||||||
|
state: latest
|
||||||
|
- name: Configuring quartz software
|
||||||
|
block:
|
||||||
|
- name: Initializing quartz website
|
||||||
|
ansible.builtin.command:
|
||||||
|
chdir: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
|
||||||
|
cmd: npx quartz create
|
||||||
|
register: stdout
|
||||||
|
changed_when: stdout.rc == 0
|
||||||
|
- name: Installing quartz plugins referenced in website template
|
||||||
|
ansible.builtin.command:
|
||||||
|
chdir: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
|
||||||
|
cmd: npx quartz plugin install --from-config
|
||||||
|
register: stdout
|
||||||
|
changed_when: stdout.rc == 0
|
||||||
|
# - name: Starting quartz site web server
|
||||||
|
# ansible.builtin.command:
|
||||||
|
# chdir: "{{ ansible_facts['user_dir'] }}/repos/.foreign/quartz"
|
||||||
|
# cmd: npx quartz build --serve
|
||||||
|
# register: stdout
|
||||||
|
# changed_when: stdout
|
||||||
18
roles/init-server/tasks/harden.yml
Normal file
18
roles/init-server/tasks/harden.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#SPDX-License-Identifier: MIT-0
|
||||||
|
---
|
||||||
|
# tasks file for roles/init-vps
|
||||||
|
- name: Checking whether administrative login used
|
||||||
|
when: ansible_user not in (admins | map(attribute="username") | list) and ansible_user != "root"
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: Must use administrative user for subsequent tasks
|
||||||
|
- name: Hardening SSH service for the Linode VPS
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: sshd_config.d/harden.conf
|
||||||
|
dest: /etc/ssh/sshd_config.d/harden.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "644"
|
||||||
|
force: true
|
||||||
|
backup: true
|
||||||
|
validate: 'sshd -t -f %s'
|
||||||
|
register: ssh_hardened
|
||||||
@@ -1,16 +1,25 @@
|
|||||||
#SPDX-License-Identifier: MIT-0
|
#SPDX-License-Identifier: MIT-0
|
||||||
---
|
---
|
||||||
# tasks file for roles/init-vps
|
# tasks file for roles/init-vps
|
||||||
- name: Creating prerequisite directory tree
|
- name: Checking whether administrative login used
|
||||||
|
when: ansible_user not in (admins | map(attribute="username") | list)
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: Must use administrative user for subsequent tasks
|
||||||
|
- name: Creating prerequisite directory tree for installation scripts
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ ansible_facts['user_dir'] }}/.local/bin"
|
path: "{{ ansible_facts['user_dir'] }}/.local/bin"
|
||||||
recurse: true
|
recurse: true
|
||||||
state: directory
|
state: directory
|
||||||
- name: Creating prerequisite directory tree
|
- name: Creating prerequisite directory tree for unarchived archives
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
path: "{{ ansible_facts['user_dir'] }}/downloads/archives/released"
|
path: "{{ ansible_facts['user_dir'] }}/downloads/archives/released"
|
||||||
recurse: true
|
recurse: true
|
||||||
state: directory
|
state: directory
|
||||||
|
- name: Creating prerequisite directory tree for package installation executables
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ ansible_facts['user_dir'] }}/.local_pkgs"
|
||||||
|
recurse: true
|
||||||
|
state: directory
|
||||||
- name: Installing Linux software
|
- name: Installing Linux software
|
||||||
when: ansible_facts["system"] == "Linux"
|
when: ansible_facts["system"] == "Linux"
|
||||||
block:
|
block:
|
||||||
@@ -19,7 +28,7 @@
|
|||||||
become: true
|
become: true
|
||||||
block:
|
block:
|
||||||
- name: Registering a package signing key
|
- name: Registering a package signing key
|
||||||
when: item.key is defined and item.key_path is defined
|
when: item.key != None and item.key_path != None
|
||||||
ansible.builtin.get_url:
|
ansible.builtin.get_url:
|
||||||
url: "{{ item.key }}"
|
url: "{{ item.key }}"
|
||||||
dest: "{{ item.key_path | default('/etc/apt/keyrings/') }}"
|
dest: "{{ item.key_path | default('/etc/apt/keyrings/') }}"
|
||||||
@@ -29,14 +38,16 @@
|
|||||||
force: true
|
force: true
|
||||||
backup: true
|
backup: true
|
||||||
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | rejectattr('key', 'search', '\\.deb$') }}"
|
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | rejectattr('key', 'search', '\\.deb$') }}"
|
||||||
|
- name: Premature stop
|
||||||
|
ansible.builtin.meta: end_play
|
||||||
- name: Installing a package signing key
|
- name: Installing a package signing key
|
||||||
when: item.key is defined
|
when: item.key != None
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
deb: "{{ item.key }}"
|
deb: "{{ item.key }}"
|
||||||
state: present
|
state: present
|
||||||
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | selectattr('key', 'search', '\\.deb$') }}"
|
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | selectattr('key', 'search', '\\.deb$') }}"
|
||||||
- name: Registering a package source
|
- name: Registering a package source
|
||||||
when: item.src_entry is defined and item.src_path is defined
|
when: item.src_entry != None and item.src_path != None
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
content: "{{ item.src_entry }}"
|
content: "{{ item.src_entry }}"
|
||||||
dest: "{{ item.src_path }}"
|
dest: "{{ item.src_path }}"
|
||||||
@@ -47,7 +58,7 @@
|
|||||||
backup: true
|
backup: true
|
||||||
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace }}"
|
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace }}"
|
||||||
- name: Installing a local package in managed node
|
- name: Installing a local package in managed node
|
||||||
when: item.uri is defined
|
when: item.uri != None
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
deb: "{{ item.uri }}"
|
deb: "{{ item.uri }}"
|
||||||
update_cache: true
|
update_cache: true
|
||||||
@@ -55,7 +66,7 @@
|
|||||||
notify: "{{ item.name }}"
|
notify: "{{ item.name }}"
|
||||||
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | selectattr('uri', 'search', '\\.deb$') }}"
|
loop: "{{ pkgs.mngr.core + pkgs.mngr.userspace | selectattr('uri', 'search', '\\.deb$') }}"
|
||||||
- name: Installing a package
|
- name: Installing a package
|
||||||
when: item.name is defined and item.uri is undefined
|
when: item.name != None and item.uri == None
|
||||||
ansible.builtin.package:
|
ansible.builtin.package:
|
||||||
name: "{{ item.name }}"
|
name: "{{ item.name }}"
|
||||||
update_cache: true
|
update_cache: true
|
||||||
@@ -65,7 +76,7 @@
|
|||||||
tags:
|
tags:
|
||||||
- get_mngr_pkgs
|
- get_mngr_pkgs
|
||||||
- name: Installing software by executing installation shell scripts
|
- name: Installing software by executing installation shell scripts
|
||||||
when: item.src is defined
|
when: item.src != None
|
||||||
block:
|
block:
|
||||||
- name: Acquiring installation shell script
|
- name: Acquiring installation shell script
|
||||||
ansible.builtin.get_url:
|
ansible.builtin.get_url:
|
||||||
|
|||||||
@@ -3,11 +3,26 @@
|
|||||||
# tasks file for roles/init-vps
|
# tasks file for roles/init-vps
|
||||||
# @TODO complete below tasks
|
# @TODO complete below tasks
|
||||||
- name: Checking whether administrative login used
|
- name: Checking whether administrative login used
|
||||||
when: ansible_facts["user_id"] not in (admins | map(attribute="username") | list)
|
when: ansible_user not in (admins | map(attribute="username") | list)
|
||||||
ansible.builtin.fail:
|
ansible.builtin.fail:
|
||||||
msg: Administrative user does not exist on managed node
|
msg: Must use administrative user for subsequent tasks
|
||||||
|
- name: Setting approved SSH authentication procedures
|
||||||
|
when: harden and ansible_facts["system"] == "Linux"
|
||||||
|
become: true
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: sshd_config.d/auth.conf
|
||||||
|
dest: /etc/ssh/sshd_config.d/auth.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "644"
|
||||||
|
force: true
|
||||||
|
backup: true
|
||||||
|
validate: "sshd -t %s"
|
||||||
|
register: ssh_authenticator
|
||||||
|
tags:
|
||||||
|
- ssh_secure_auth
|
||||||
- name: Prohibiting SSH root login
|
- name: Prohibiting SSH root login
|
||||||
when: harden
|
when: harden and ansible_facts["system"] == "Linux"
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
src: sshd_config.d/denyroot.conf
|
src: sshd_config.d/denyroot.conf
|
||||||
@@ -19,7 +34,7 @@
|
|||||||
backup: true
|
backup: true
|
||||||
validate: "sshd -t %s"
|
validate: "sshd -t %s"
|
||||||
- name: Create groups for FTP services
|
- name: Create groups for FTP services
|
||||||
when: "'internal-sftp' in item.service or 'proftpd' in item.service or 'vsftpd' in item.service"
|
when: "'sftp-server' in item.service or 'proftpd' in item.service or 'vsftpd' in item.service"
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.group:
|
ansible.builtin.group:
|
||||||
name: "{{ item.username }}"
|
name: "{{ item.username }}"
|
||||||
@@ -28,14 +43,27 @@
|
|||||||
loop: "{{ sys_users }}"
|
loop: "{{ sys_users }}"
|
||||||
register: ftp_groups
|
register: ftp_groups
|
||||||
- name: Configuring SFTP for FTP group
|
- name: Configuring SFTP for FTP group
|
||||||
|
when: ansible_facts["system"] == "Linux"
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.template:
|
ansible.builtin.blockinfile:
|
||||||
src: sshd_config.d/sftp.conf.j2
|
# src: sshd_config.d/sftp.conf.j2
|
||||||
dest: /etc/ssh/sshd_config.d/sftp.conf
|
# dest: /etc/ssh/sshd_config.d/sftp.conf
|
||||||
|
path: /etc/ssh/sshd_config.d/sftp.conf
|
||||||
|
block: |
|
||||||
|
Match Group {{ item.name }}
|
||||||
|
ForceCommand internal-sftp -d /%u
|
||||||
|
ChrootDirectory /srv/{{ item.name}}
|
||||||
|
AllowAgentForwarding no
|
||||||
|
AllowTcpForwarding no
|
||||||
|
X11Forwarding no
|
||||||
|
append_newline: true
|
||||||
|
marker_begin: "BEGIN FTP GROUP SSH MATCH BLOCK"
|
||||||
|
create: true
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "644"
|
mode: "644"
|
||||||
force: true
|
|
||||||
backup: true
|
backup: true
|
||||||
validate: "sshd -t %s"
|
validate: "sshd -t %s"
|
||||||
|
state: present
|
||||||
|
loop: "{{ ftp_groups.results }}"
|
||||||
register: configured_sftp
|
register: configured_sftp
|
||||||
@@ -1,443 +0,0 @@
|
|||||||
#SPDX-License-Identifier: MIT-0
|
|
||||||
---
|
|
||||||
# tasks file for roles/init-vps
|
|
||||||
# @NOTE server deployment method is based on task tags compiled herein
|
|
||||||
# @TODO review 'loop' task attribute return values and make compliant changes
|
|
||||||
- name: Finding SSH public keys for root
|
|
||||||
ansible.builtin.find:
|
|
||||||
paths: "{{ cnode_homedir | default('/home/' ~ ansible_user ~ '/.ssh') }}" # @TODO define 'cnode_homedir' in playbook
|
|
||||||
patterns: "{{ ['^'] | product(keys) | map('join') | list }}"
|
|
||||||
file_type: file
|
|
||||||
use_regex: true
|
|
||||||
register: ssh_keypairs
|
|
||||||
- name: Bootstrapping VPS
|
|
||||||
block:
|
|
||||||
- name: Creating VPS via Linode VPS service API
|
|
||||||
block:
|
|
||||||
- name: Creating the VPS
|
|
||||||
linode.cloud.instance:
|
|
||||||
api_token: "{{ token }}"
|
|
||||||
label: "{{ instance }}"
|
|
||||||
type: g6-standard-2
|
|
||||||
image: "{{ operating_system }}"
|
|
||||||
disk_encryption: enabled
|
|
||||||
region: "{{ origin }}"
|
|
||||||
private_ip: true
|
|
||||||
root_pass: "{{ password }}"
|
|
||||||
authorized_keys: "{{ ssh_keypairs.files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | map('lookup', 'file') | list }}"
|
|
||||||
state: present
|
|
||||||
register: new_instance
|
|
||||||
- name: Waiting for that VPS to come online
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
delegate_facts: true
|
|
||||||
ansible.builtin.wait_for_connection:
|
|
||||||
delay: 20
|
|
||||||
timeout: 300
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
- name: Checking if that VPS has required operating system
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
delegate_facts: true
|
|
||||||
when: ansible_facts["system"] != "Linux"
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: Unsupported operating system found
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
- name: Checking if that VPS has required Linux distro
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
delegate_facts: true
|
|
||||||
when: ansible_facts["system"] == "Linux" and ansible_facts["os_family"] != "Debian"
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: Unsupported Linux distro found
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
tags:
|
|
||||||
- linode
|
|
||||||
tags:
|
|
||||||
- vps
|
|
||||||
- name: Bootstrapping homeserver
|
|
||||||
block:
|
|
||||||
- name: Installing operating system or distro in server
|
|
||||||
when: operating_system is defined
|
|
||||||
block:
|
|
||||||
- name: Creating a server
|
|
||||||
block: []
|
|
||||||
tags:
|
|
||||||
- unimplemented
|
|
||||||
- name: Waiting for that VPS to come online
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
delegate_facts: true
|
|
||||||
ansible.builtin.wait_for_connection:
|
|
||||||
delay: 20
|
|
||||||
timeout: 300
|
|
||||||
vars:
|
|
||||||
ansible_user: root
|
|
||||||
- name: Checking if that server has required operating system
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
delegate_facts: true
|
|
||||||
when: ansible_facts["system"] != "Linux"
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: Unsupported operating system found
|
|
||||||
vars:
|
|
||||||
ansible_user: root
|
|
||||||
- name: Checking if that server has required Linux distro
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
delegate_facts: true
|
|
||||||
when: ansible_facts["system"] == "Linux" and ansible_facts["os_family"] != "Debian"
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: Unsupported Linux distro found
|
|
||||||
vars:
|
|
||||||
ansible_user: root
|
|
||||||
- name: Providing authorized keys for server root account
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
delegate_facts: true
|
|
||||||
ansible.posix.authorized_key:
|
|
||||||
user: "{{ ansible_facts['user_id'] }}"
|
|
||||||
key: "{{ lookup('file', item) }}"
|
|
||||||
state: present
|
|
||||||
vars:
|
|
||||||
ansible_root: root
|
|
||||||
loop: "{{ ssh_keypairs.files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | list }}"
|
|
||||||
tags:
|
|
||||||
- lan
|
|
||||||
- name: Starting SSH hardening
|
|
||||||
when: harden
|
|
||||||
delegate_facts: true
|
|
||||||
block:
|
|
||||||
- name: Hardening SSH service for the Linode VPS
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: sshd_config.d/harden.conf
|
|
||||||
dest: /etc/ssh/sshd_config.d/harden.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
validate: "sshd -t %s"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
register: ssh_hardened
|
|
||||||
tags:
|
|
||||||
- linode
|
|
||||||
- name: Hardening SSH service for the server
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: sshd_config.d/harden.conf
|
|
||||||
dest: /etc/ssh/sshd_config.d/harden.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
validate: "sshd -t %s"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
register: ssh_hardened
|
|
||||||
tags:
|
|
||||||
- lan
|
|
||||||
- name: Starting user and group creation for SSH access
|
|
||||||
block:
|
|
||||||
- name: Creating group remote for managing SSH access
|
|
||||||
delegate_facts: true
|
|
||||||
block:
|
|
||||||
- name: In the Linode VPS
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
ansible.builtin.group:
|
|
||||||
name: remote
|
|
||||||
system: true
|
|
||||||
state: present
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
register: remote_group
|
|
||||||
tags:
|
|
||||||
- linode
|
|
||||||
- name: In the server
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
ansible.builtin.group:
|
|
||||||
name: remote
|
|
||||||
system: true
|
|
||||||
state: present
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
register: remote_group
|
|
||||||
tags:
|
|
||||||
- lan
|
|
||||||
- name: Creating an administrative user
|
|
||||||
delegate_facts: true
|
|
||||||
when: ansible_facts["system"] == "Linux"
|
|
||||||
block:
|
|
||||||
- name: In the Linode VPS
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
ansible.builtin.user:
|
|
||||||
name: "{{ item.username }}"
|
|
||||||
comment: administrator
|
|
||||||
group: "{{ item.username }}"
|
|
||||||
groups:
|
|
||||||
- "{{ remote_group.name }}"
|
|
||||||
- sudo # @NOTE used by Debian
|
|
||||||
append: true
|
|
||||||
generate_ssh_key: true
|
|
||||||
create_home: true
|
|
||||||
password: "{{ item.password }}"
|
|
||||||
shell: "/bin/bash"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
loop: "{{ admins }}"
|
|
||||||
register: admin_users
|
|
||||||
tags:
|
|
||||||
- linode
|
|
||||||
- name: In the server
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
ansible.builtin.user:
|
|
||||||
name: "{{ item.username }}"
|
|
||||||
comment: administrator
|
|
||||||
group: "{{ item.username }}"
|
|
||||||
groups:
|
|
||||||
- "{{ remote_group.name }}"
|
|
||||||
- sudo # @NOTE used by Debian
|
|
||||||
append: true
|
|
||||||
generate_ssh_key: true
|
|
||||||
create_home: true
|
|
||||||
password: "{{ item.password }}"
|
|
||||||
shell: "/bin/bash"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
loop: "{{ admins }}"
|
|
||||||
register: admin_users
|
|
||||||
tags:
|
|
||||||
- lan
|
|
||||||
- name: Finding SSH public keys for an administrative user
|
|
||||||
when: item.username in (admin_users.results | map(attribute="name") | list)
|
|
||||||
ansible.builtin.find:
|
|
||||||
paths: "{{ cnode_homedir | default('/home/' ~ ansible_user ~ '/.ssh') }}" # @TODO define 'cnode_homedir' in playbook
|
|
||||||
patterns: "{{ ['^'] | product(item.keys) | map('join') | list }}"
|
|
||||||
file_type: file
|
|
||||||
use_regex: true
|
|
||||||
loop: "{{ admins }}"
|
|
||||||
register: admin_ssh_keypairs
|
|
||||||
- name: Authorizing SSH public key for an administrative user
|
|
||||||
delegate_facts: true
|
|
||||||
block:
|
|
||||||
- name: In the Linode VPS
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
ansible.posix.authorized_key:
|
|
||||||
user: "{{ admin_users.results[idx] }}"
|
|
||||||
key: "{{ admin_ssh_keypairs.results[idx].files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | map('lookup', 'file') | list | map('join','\n') }}"
|
|
||||||
state: present
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
loop: "{{ admin_users.results }}"
|
|
||||||
loop_control:
|
|
||||||
index_var: idx
|
|
||||||
register: ssh_authorizations
|
|
||||||
tags:
|
|
||||||
- linode
|
|
||||||
- name: In the server
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
ansible.posix.authorized_key:
|
|
||||||
user: "{{ admin_users.results[idx] }}"
|
|
||||||
key: "{{ admin_ssh_keypairs.results[idx].files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | map('lookup', 'file') | list | map('join','\n') }}"
|
|
||||||
state: present
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
loop: "{{ admin_users.results }}"
|
|
||||||
loop_control:
|
|
||||||
index_var: idx
|
|
||||||
register: ssh_authorizations
|
|
||||||
tags:
|
|
||||||
- lan
|
|
||||||
- name: Allowing sole SSH access to users in group remote
|
|
||||||
delegate_facts: true
|
|
||||||
block:
|
|
||||||
- name: In Linode VPS
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: sshd_config.d/allowance.conf.j2 # @TODO create corresponding role template file
|
|
||||||
dest: /etc/ssh/sshd_config.d/allowance.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
validate: "sshd -t %s"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
register: ssh_gatekept
|
|
||||||
tags:
|
|
||||||
- linode
|
|
||||||
- name: In Linode VPS
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: sshd_config.d/allowance.conf.j2 # @TODO create corresponding role template file
|
|
||||||
dest: /etc/ssh/sshd_config.d/allowance.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
validate: "sshd -t %s"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
register: ssh_gatekept
|
|
||||||
tags:
|
|
||||||
- lan
|
|
||||||
- name: Setting approved SSH authentication procedures
|
|
||||||
when: harden
|
|
||||||
delegate_facts: true
|
|
||||||
block:
|
|
||||||
- name: In the Linode VPS
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: sshd_config.d/auth.conf
|
|
||||||
dest: /etc/ssh/sshd_config.d/auth.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
validate: "sshd -t %s"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
register: ssh_authenticator
|
|
||||||
tags:
|
|
||||||
- linode
|
|
||||||
- name: In the server
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
ansible.builtin.copy:
|
|
||||||
src: sshd_config.d/auth.conf
|
|
||||||
dest: /etc/ssh/sshd_config.d/auth.conf
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
validate: "sshd -t %s"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
register: ssh_authenticator
|
|
||||||
tags:
|
|
||||||
- lan
|
|
||||||
- name: Installing core packages
|
|
||||||
delegate_facts: true
|
|
||||||
block:
|
|
||||||
- name: In the Linode VPS
|
|
||||||
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
|
||||||
block:
|
|
||||||
- name: Registering a package signing key
|
|
||||||
when: ansible_facts["os_family"] == "Debian" and item.key is defined and item.key_path is defined
|
|
||||||
ansible.builtin.get_url:
|
|
||||||
url: "{{ item.key }}"
|
|
||||||
dest: "{{ item.key_path | default('/etc/apt/keyrings/') }}"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
loop: "{{ pkgs.mngr.core | rejectattr('key', 'search', '\\.deb$') }}"
|
|
||||||
- name: Installing a package signing key
|
|
||||||
when: ansible_facts["os_family"] == "Debian" and item.key is defined
|
|
||||||
ansible.builtin.apt:
|
|
||||||
deb: "{{ item.key }}"
|
|
||||||
state: latest
|
|
||||||
loop: "{{ pkgs.mngr.core | selectattr('key', 'search', '\\.deb$') }}"
|
|
||||||
- name: Registering a package source
|
|
||||||
when: ansible_facts["os_family"] == "Debian" and item.src_entry is defined and item.src_path is defined
|
|
||||||
ansible.builtin.copy:
|
|
||||||
content: "{{ item.src_entry }}"
|
|
||||||
dest: "{{ item.src_path }}"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
loop: "{{ pkgs.mngr.core }}"
|
|
||||||
- name: Installing a local package in managed node
|
|
||||||
when: ansible_facts["os_family"] == "Debian" and item.uri is defined
|
|
||||||
ansible.builtin.apt:
|
|
||||||
deb: "{{ item.uri }}"
|
|
||||||
update_cache: true
|
|
||||||
state: latest
|
|
||||||
loop: "{{ pkgs.mngr.core | selectattr('uri', 'search', '\\.deb$') }}"
|
|
||||||
- name: Installing a package
|
|
||||||
when: item.name is defined and item.uri is undefined
|
|
||||||
ansible.builtin.package:
|
|
||||||
name: "{{ item.name }}"
|
|
||||||
update_cache: true
|
|
||||||
state: latest
|
|
||||||
notify: "{{ item.name }}" # @TODO create corresponding roles/init-vps handlers
|
|
||||||
loop: "{{ pkgs.mngr.core| rejectattr('uri', 'search', '\\.deb$') }}"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
tags:
|
|
||||||
- linode
|
|
||||||
- name: In the server
|
|
||||||
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
|
||||||
block:
|
|
||||||
- name: Registering a package signing key
|
|
||||||
when: ansible_facts["os_family"] == "Debian" and item.key is defined and item.key_path is defined
|
|
||||||
ansible.builtin.get_url:
|
|
||||||
url: "{{ item.key }}"
|
|
||||||
dest: "{{ item.key_path | default('/etc/apt/keyrings/') }}"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
loop: "{{ pkgs.mngr.core | rejectattr('key', 'search', '\\.deb$') }}"
|
|
||||||
- name: Installing a package signing key
|
|
||||||
when: ansible_facts["os_family"] == "Debian" and item.key is defined
|
|
||||||
ansible.builtin.apt:
|
|
||||||
deb: "{{ item.key }}"
|
|
||||||
state: latest
|
|
||||||
loop: "{{ pkgs.mngr.core | selectattr('key', 'search', '\\.deb$') }}"
|
|
||||||
- name: Registering a package source
|
|
||||||
when: ansible_facts["os_family"] == "Debian" and item.src_entry is defined and item.src_path is defined
|
|
||||||
ansible.builtin.copy:
|
|
||||||
content: "{{ item.src_entry }}"
|
|
||||||
dest: "{{ item.src_path }}"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "644"
|
|
||||||
force: true
|
|
||||||
backup: true
|
|
||||||
loop: "{{ pkgs.mngr.core }}"
|
|
||||||
- name: Installing a local package in managed node
|
|
||||||
when: ansible_facts["os_family"] == "Debian" and item.uri is defined
|
|
||||||
ansible.builtin.apt:
|
|
||||||
deb: "{{ item.uri }}"
|
|
||||||
update_cache: true
|
|
||||||
state: latest
|
|
||||||
notify: "{{ item.name }}"
|
|
||||||
loop: "{{ pkgs.mngr.core | selectattr('uri', 'search', '\\.deb$') }}"
|
|
||||||
- name: Installing a package
|
|
||||||
when: item.name is defined and item.uri is undefined
|
|
||||||
ansible.builtin.package:
|
|
||||||
name: "{{ item.name }}"
|
|
||||||
update_cache: true
|
|
||||||
state: latest
|
|
||||||
notify: "{{ item.name }}" # @TODO create corresponding roles/init-vps handlers
|
|
||||||
loop: "{{ pkgs.mngr.core| rejectattr('uri', 'search', '\\.deb$') }}"
|
|
||||||
vars:
|
|
||||||
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
|
||||||
ansible_user: root
|
|
||||||
tags:
|
|
||||||
- lan
|
|
||||||
tags:
|
|
||||||
- get_pkgs
|
|
||||||
91
roles/init-server/tasks/spawn.yml
Normal file
91
roles/init-server/tasks/spawn.yml
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#SPDX-License-Identifier: MIT-0
|
||||||
|
---
|
||||||
|
# tasks file for roles/init-vps
|
||||||
|
# @NOTE server deployment method is based on task tags compiled herein
|
||||||
|
# @TODO review 'loop' task attribute return values and make compliant changes
|
||||||
|
- name: Finding SSH public keys for root
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: "{{ cnode_homedir | default('/home/' ~ ansible_user ~ '/.ssh') }}" # @TODO define 'cnode_homedir' in playbook
|
||||||
|
patterns: "{{ ['^'] | product(keys) | map('join') | list }}"
|
||||||
|
file_type: file
|
||||||
|
use_regex: true
|
||||||
|
register: ssh_keypairs
|
||||||
|
- name: Bootstrapping VPS
|
||||||
|
block:
|
||||||
|
- name: Creating VPS via Linode VPS service API
|
||||||
|
block:
|
||||||
|
- name: Creating the VPS
|
||||||
|
linode.cloud.instance:
|
||||||
|
api_token: "{{ token }}"
|
||||||
|
label: "{{ instance }}"
|
||||||
|
type: g6-standard-2
|
||||||
|
image: "{{ operating_system }}"
|
||||||
|
disk_encryption: enabled
|
||||||
|
region: "{{ origin }}"
|
||||||
|
private_ip: true
|
||||||
|
root_pass: "{{ password }}"
|
||||||
|
authorized_keys: "{{ ssh_keypairs.files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | map('lookup', 'file') | list }}"
|
||||||
|
state: present
|
||||||
|
register: new_instance
|
||||||
|
- name: Waiting for that VPS to come online
|
||||||
|
delegate_to: "{{ new_instance.instance[ip_pref][0] }}"
|
||||||
|
delegate_facts: true
|
||||||
|
ansible.builtin.wait_for_connection:
|
||||||
|
delay: 20
|
||||||
|
timeout: 300
|
||||||
|
vars:
|
||||||
|
ansible_ssh_private_key_file: "{{ chosen_privkey | default(ssh_keypairs.files | rejectattr('path', 'search', '\\.pub$') | map(attribute='path') | list | random) }}" # @TODO define 'chosen_privkey'in playbook
|
||||||
|
ansible_user: root
|
||||||
|
tags:
|
||||||
|
- linode
|
||||||
|
tags:
|
||||||
|
- vps
|
||||||
|
- name: Bootstrapping homeserver
|
||||||
|
block:
|
||||||
|
- name: Installing operating system or distro in server
|
||||||
|
when: operating_system != None
|
||||||
|
block:
|
||||||
|
- name: Creating a server
|
||||||
|
block: []
|
||||||
|
tags:
|
||||||
|
- unimplemented
|
||||||
|
- name: Waiting for that server to come online
|
||||||
|
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
||||||
|
delegate_facts: true
|
||||||
|
remote_user: root
|
||||||
|
ansible.builtin.wait_for_connection:
|
||||||
|
delay: 20
|
||||||
|
timeout: 300
|
||||||
|
vars:
|
||||||
|
ansible_user: root
|
||||||
|
- name: Checking if that server has required operating system
|
||||||
|
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
||||||
|
delegate_facts: true
|
||||||
|
remote_user: root
|
||||||
|
when: ansible_facts["system"] != "Linux"
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: Unsupported operating system found
|
||||||
|
vars:
|
||||||
|
ansible_user: root
|
||||||
|
- name: Checking if that server has required Linux distro
|
||||||
|
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
||||||
|
delegate_facts: true
|
||||||
|
remote_user: root
|
||||||
|
when: ansible_facts["system"] == "Linux" and ansible_facts["os_family"] != "Debian"
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: Unsupported Linux distro found
|
||||||
|
vars:
|
||||||
|
ansible_user: root
|
||||||
|
- name: Providing authorized keys for server root account
|
||||||
|
delegate_to: "{{ hostvars[instance]['ansible_default_' ~ ip_pref].address }}"
|
||||||
|
delegate_facts: true
|
||||||
|
remote_user: root
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: "{{ ansible_user }}"
|
||||||
|
key: "{{ lookup('file', item) }}"
|
||||||
|
state: present
|
||||||
|
vars:
|
||||||
|
ansible_root: root
|
||||||
|
loop: "{{ ssh_keypairs.files | selectattr('path', 'search', '\\.pub$') | map(attribute='path') | list }}"
|
||||||
|
tags:
|
||||||
|
- lan
|
||||||
93
roles/init-server/tasks/ssh-users.yml
Normal file
93
roles/init-server/tasks/ssh-users.yml
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#SPDX-License-Identifier: MIT-0
|
||||||
|
---
|
||||||
|
# tasks file for roles/init-vps
|
||||||
|
- name: Checking whether administrative or root login used
|
||||||
|
when: ansible_user not in (admins | map(attribute="username") | list) and ansible_user != "root"
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: Must use administrative or root user for subsequent tasks
|
||||||
|
- name: Starting user and group creation for SSH access
|
||||||
|
block:
|
||||||
|
- name: Creating group remote for managing SSH access
|
||||||
|
become: true
|
||||||
|
ansible.builtin.group:
|
||||||
|
name: remote
|
||||||
|
system: true
|
||||||
|
state: present
|
||||||
|
register: remote_group
|
||||||
|
tags:
|
||||||
|
- lan
|
||||||
|
- name: Creating an administrative user
|
||||||
|
become: true
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ item.username }}"
|
||||||
|
comment: administrator
|
||||||
|
groups:
|
||||||
|
- "{{ remote_group.name | default('remote') }}"
|
||||||
|
- sudo # @NOTE used by Debian
|
||||||
|
append: true
|
||||||
|
generate_ssh_key: true
|
||||||
|
create_home: true
|
||||||
|
password: "{{ item.password }}"
|
||||||
|
shell: "/bin/bash"
|
||||||
|
loop: "{{ admins }}"
|
||||||
|
register: admin_users
|
||||||
|
tags:
|
||||||
|
- lan
|
||||||
|
- name: Finding SSH public keys for an administrative user
|
||||||
|
delegate_facts: true
|
||||||
|
delegate_to: localhost
|
||||||
|
when: item.username in (admin_users.results | map(attribute="name") | list)
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths: "{{ local_facts['user_dir'] }}/.ssh" # @TODO define 'cnode_homedir' in playbook
|
||||||
|
patterns: "{{ ['^'] | product(item.ssh_keys) | map('join') | list }}"
|
||||||
|
file_type: file
|
||||||
|
use_regex: true
|
||||||
|
loop: "{{ admins }}"
|
||||||
|
register: admin_ssh_keypairs
|
||||||
|
- name: Creating list wherein each SSH public key is associated with a user
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
pubkey_users: "{{ [admin_users.results[idx].name] | product(admin_ssh_keypairs.results[idx].files | selectattr('path', 'search', '\\.pub$') | map(attribute='path')) }}"
|
||||||
|
loop: "{{ admins }}"
|
||||||
|
loop_control:
|
||||||
|
index_var: idx
|
||||||
|
- name: Authorizing SSH public key for an administrative user
|
||||||
|
become: true
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: "{{ item[0] }}"
|
||||||
|
key: "{{ lookup('file', item[1]) }}"
|
||||||
|
state: present
|
||||||
|
loop: "{{ pubkey_users }}"
|
||||||
|
register: ssh_authorizations
|
||||||
|
tags:
|
||||||
|
- lan
|
||||||
|
- name: Setting approved SSH authentication procedures
|
||||||
|
when: harden and ansible_facts["system"] == "Linux"
|
||||||
|
become: true
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: sshd_config.d/auth.conf
|
||||||
|
dest: /etc/ssh/sshd_config.d/auth.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "644"
|
||||||
|
force: true
|
||||||
|
backup: true
|
||||||
|
validate: "sshd -t -f %s"
|
||||||
|
register: ssh_authenticator
|
||||||
|
tags:
|
||||||
|
- lan
|
||||||
|
- ssh_secure_auth
|
||||||
|
- name: Allowing sole SSH access to users in group remote
|
||||||
|
when: ansible_facts["system"] == "Linux"
|
||||||
|
become: true
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: sshd_config.d/allowance.conf.j2 # @TODO create corresponding role template file
|
||||||
|
dest: /etc/ssh/sshd_config.d/allowance.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "644"
|
||||||
|
force: true
|
||||||
|
backup: true
|
||||||
|
validate: "sshd -t -f %s"
|
||||||
|
register: ssh_gatekept
|
||||||
|
tags:
|
||||||
|
- lan
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{% for item in ftp_groups.results %}
|
|
||||||
Match Group {{ item.name }}
|
|
||||||
ForceCommand internal-sftp -d /%u
|
|
||||||
ChrootDirectory /srv/{{ item.name}}
|
|
||||||
AllowAgentForwarding no
|
|
||||||
AllowTcpForwarding no
|
|
||||||
X11Forwarding no
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
Reference in New Issue
Block a user