migrate to git.charlotte.sh

This commit is contained in:
Charlotte Croce 2025-04-19 23:42:08 -04:00
commit fbd588721e
412 changed files with 13750 additions and 0 deletions

View file

@ -0,0 +1,2 @@
[defaults]
host_key_checking = false

View file

@ -0,0 +1,9 @@
[apache]
ansible1-charlotte
[webmin]
ansible2-charlotte
[windows]
mgmt01-charlotte
wks01-charlotte
[windows:vars]
ansible_shell_type=powershell

View file

@ -0,0 +1,85 @@
- name: Rocky Linux Security Configuration
hosts: ansible1-charlotte
become: yes
gather_facts: yes
tasks:
# Create security admin group first
- name: Create security admin group
group:
name: secadmin
state: present
tags: fs_perms
# ============================================================
# SYSTEM ADMINISTRATION ELEMENT: File System Permissions
# ============================================================
# Create parent directory first
- name: Create data directory
file:
path: /data
state: directory
mode: '0755'
owner: root
group: root
tags: fs_perms
- name: Create secure data directory
file:
path: /data/secure
state: directory
mode: '0750'
owner: root
group: secadmin
tags: fs_perms
- name: Set secure permissions on sensitive files
file:
path: "{{ item.path }}"
mode: "{{ item.mode }}"
owner: "{{ item.owner }}"
group: "{{ item.group }}"
with_items:
- { path: '/etc/passwd', mode: '0644', owner: 'root', group: 'root' }
- { path: '/etc/shadow', mode: '0400', owner: 'root', group: 'root' }
- { path: '/etc/ssh/sshd_config', mode: '0600', owner: 'root', group: 'root' }
tags: fs_perms
# ============================================================
# SYSTEM HARDENING ELEMENT: Firewall Configuration
# ============================================================
- name: Ensure firewalld is installed
dnf:
name: firewalld
state: present
tags: firewall
- name: Enable and start firewalld
service:
name: firewalld
state: started
enabled: yes
tags: firewall
- name: Allow necessary services
firewalld:
service: "{{ item }}"
permanent: yes
state: enabled
immediate: yes
with_items:
- ssh
- http
- https
tags: firewall
- name: Block all other ports
firewalld:
port: "{{ item }}"
permanent: yes
state: disabled
immediate: yes
with_items:
- 21/tcp
- 23/tcp
- 25/tcp
tags: firewall

View file

@ -0,0 +1,105 @@
- name: Windows Security Configuration
hosts: windows
gather_facts: yes
tasks:
# ============================================================
# SYSTEM ADMINISTRATION ELEMENT: Shared Folder Management
# ============================================================
- name: Create secure shared folder
win_file:
path: C:\SecureShare
state: directory
tags: file_mgmt
- name: Share the secure folder
win_share:
name: SecureData
path: C:\SecureShare
description: "Secure data repository"
list: yes
full: Administrators
read: "Domain Users"
deny: "Everyone"
tags: file_mgmt
- name: Set NTFS permissions on secure folder
win_acl:
path: C:\SecureShare
user: Administrators
rights: FullControl
type: allow
state: present
inheritance_flags: "ContainerInherit,ObjectInherit"
tags: ntfs_perms
- name: Add read permissions for authenticated users
win_acl:
path: C:\SecureShare
user: "Authenticated Users"
rights: ReadAndExecute
type: allow
state: present
inheritance_flags: "ContainerInherit,ObjectInherit"
tags: ntfs_perms
# ============================================================
# SYSTEM HARDENING ELEMENT: Disable Unnecessary Services
# ============================================================
- name: Check for service existence
win_shell: Get-Service -Name "{{ item }}" -ErrorAction SilentlyContinue
register: service_check
with_items:
- XblGameSave # Xbox Game Saving Service
- XboxNetApiSvc # Xbox Live Networking Service
- DiagTrack # Connected User Experiences and Telemetry
- dmwappushservice # WAP Push Message Routing Service
failed_when: false
changed_when: false
tags: hardening
- name: Disable unnecessary services if they exist
win_service:
name: "{{ item.item }}"
state: stopped
start_mode: disabled
with_items: "{{ service_check.results }}"
when: item.rc == 0
tags: hardening
- name: Report on services not found
debug:
msg: "Service {{ item.item }} not found on {{ inventory_hostname }}"
with_items: "{{ service_check.results }}"
when: item.rc != 0
tags: hardening
# ============================================================
# AD DS GPO ELEMENT 1: Password Policy
# ============================================================
- name: Configure password policy
win_security_policy:
section: System Access
key: "{{ item.key }}"
value: "{{ item.value }}"
with_items:
- { key: PasswordComplexity, value: 1 } # Enable password complexity
- { key: MinimumPasswordLength, value: 12 } # 12 character minimum
- { key: PasswordHistorySize, value: 24 } # Remember 24 passwords
when: inventory_hostname in ['wks01-charlotte', 'mgmt01-charlotte']
tags: gpo_password
# ============================================================
# AD DS GPO ELEMENT 2: Account Lockout Policy
# ============================================================
- name: Configure account lockout policy
win_security_policy:
section: System Access
key: "{{ item.key }}"
value: "{{ item.value }}"
with_items:
- { key: LockoutBadCount, value: 5 } # 5 failed attempts
- { key: ResetLockoutCount, value: 30 } # Reset counter after 30 minutes
- { key: LockoutDuration, value: 30 } # Lock for 30 minutes
when: inventory_hostname in ['wks01-charlotte', 'mgmt01-charlotte']
tags: gpo_lockout

View file

@ -0,0 +1,39 @@
- name: apache sys265
hosts: apache
become: true # Run all tasks with sudo/root privileges
vars:
install_utilities: false
firewalld_enable: true
ansible_os_family: RedHat
ansible_distribution: CentOS # required because role searches for Rocky config files
roles:
- geerlingguy.apache # apply the apache installation role
handlers: # will run when a task has notify:name parameter
- name: reload firewall # runs after adding firewall rule
command: firewall-cmd --reload
tasks:
# open port 443 in firewall for apache web interface
- name: add firewall rule
firewalld:
port: "{{ item }}"
permanent: true
immediate: true
state: enabled
loop:
- 80/tcp
- 443/tcp
notify: reload firewall
- name: install apache
yum:
name: httpd
state: present # will only install if not already
- name: enable and start apache service
systemd:
name: httpd
enabled: true
state: started
daemon_reload: yes # reload systemd to recognize new service

View file

@ -0,0 +1,3 @@
skip_list:
- 'yaml'
- 'role-name'

View file

@ -0,0 +1,4 @@
# These are supported funding model platforms
---
github: geerlingguy
patreon: geerlingguy

View file

@ -0,0 +1,67 @@
---
name: CI
'on':
pull_request:
push:
branches:
- master
schedule:
- cron: "0 5 * * 0"
defaults:
run:
working-directory: 'geerlingguy.apache'
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Check out the codebase.
uses: actions/checkout@v4
with:
path: 'geerlingguy.apache'
- name: Set up Python 3.
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install test dependencies.
run: pip3 install yamllint
- name: Lint code.
run: |
yamllint .
molecule:
name: Molecule
runs-on: ubuntu-latest
strategy:
matrix:
distro:
- rockylinux8
- ubuntu2004
- debian10
steps:
- name: Check out the codebase.
uses: actions/checkout@v4
with:
path: 'geerlingguy.apache'
- name: Set up Python 3.
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install test dependencies.
run: pip3 install ansible molecule molecule-plugins[docker] docker
- name: Run Molecule tests.
run: molecule test
env:
PY_COLORS: '1'
ANSIBLE_FORCE_COLOR: '1'
MOLECULE_DISTRO: ${{ matrix.distro }}

View file

@ -0,0 +1,40 @@
---
# This workflow requires a GALAXY_API_KEY secret present in the GitHub
# repository or organization.
#
# See: https://github.com/marketplace/actions/publish-ansible-role-to-galaxy
# See: https://github.com/ansible/galaxy/issues/46
name: Release
'on':
push:
tags:
- '*'
defaults:
run:
working-directory: 'geerlingguy.apache'
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Check out the codebase.
uses: actions/checkout@v4
with:
path: 'geerlingguy.apache'
- name: Set up Python 3.
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install Ansible.
run: pip3 install ansible-core
- name: Trigger a new import on Galaxy.
run: >-
ansible-galaxy role import --api-key ${{ secrets.GALAXY_API_KEY }}
$(echo ${{ github.repository }} | cut -d/ -f1) $(echo ${{ github.repository }} | cut -d/ -f2)

View file

@ -0,0 +1,34 @@
---
name: Close inactive issues
'on':
schedule:
- cron: "55 18 * * 1" # semi-random time
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v8
with:
days-before-stale: 120
days-before-close: 60
exempt-issue-labels: bug,pinned,security,planned
exempt-pr-labels: bug,pinned,security,planned
stale-issue-label: "stale"
stale-pr-label: "stale"
stale-issue-message: |
This issue has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution!
Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale.
close-issue-message: |
This issue has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details.
stale-pr-message: |
This pr has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution!
Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale.
close-pr-message: |
This pr has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details.
repo-token: ${{ secrets.GITHUB_TOKEN }}

View file

@ -0,0 +1,5 @@
*.retry
*/__pycache__
*.pyc
.cache

View file

@ -0,0 +1,10 @@
---
extends: default
rules:
line-length:
max: 120
level: warning
ignore: |
.github/workflows/stale.yml

View file

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2017 Jeff Geerling
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,208 @@
# Ansible Role: Apache 2.x
[![CI](https://github.com/geerlingguy/ansible-role-apache/workflows/CI/badge.svg?event=push)](https://github.com/geerlingguy/ansible-role-apache/actions?query=workflow%3ACI)
An Ansible Role that installs Apache 2.x on RHEL/CentOS, Debian/Ubuntu, SLES and Solaris.
## Requirements
If you are using SSL/TLS, you will need to provide your own certificate and key files. You can generate a self-signed certificate with a command like `openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout example.key -out example.crt`.
If you are using Apache with PHP, I recommend using the `geerlingguy.php` role to install PHP, and you can either use mod_php (by adding the proper package, e.g. `libapache2-mod-php5` for Ubuntu, to `php_packages`), or by also using `geerlingguy.apache-php-fpm` to connect Apache to PHP via FPM. See that role's README for more info.
## Role Variables
Available variables are listed below, along with default values (see `defaults/main.yml`):
```yaml
apache_enablerepo: ""
```
The repository to use when installing Apache (only used on RHEL/CentOS systems). If you'd like later versions of Apache than are available in the OS's core repositories, use a repository like EPEL (which can be installed with the `geerlingguy.repo-epel` role).
```yaml
apache_listen_ip: "*"
apache_listen_port: 80
apache_listen_port_ssl: 443
```
The IP address and ports on which apache should be listening. Useful if you have another service (like a reverse proxy) listening on port 80 or 443 and need to change the defaults.
```yaml
apache_create_vhosts: true
apache_vhosts_filename: "vhosts.conf"
apache_vhosts_template: "vhosts.conf.j2"
```
If set to true, a vhosts file, managed by this role's variables (see below), will be created and placed in the Apache configuration folder. If set to false, you can place your own vhosts file into Apache's configuration folder and skip the convenient (but more basic) one added by this role. You can also override the template used and set a path to your own template, if you need to further customize the layout of your VirtualHosts.
```yaml
apache_remove_default_vhost: false
```
On Debian/Ubuntu, a default virtualhost is included in Apache's configuration. Set this to `true` to remove that default virtualhost configuration file.
```yaml
apache_global_vhost_settings: |
DirectoryIndex index.php index.html
# Add other global settings on subsequent lines.
```
You can add or override global Apache configuration settings in the role-provided vhosts file (assuming `apache_create_vhosts` is true) using this variable. By default it only sets the DirectoryIndex configuration.
```yaml
apache_vhosts:
# Additional optional properties: 'serveradmin, serveralias, extra_parameters'.
- servername: "local.dev"
documentroot: "/var/www/html"
```
Add a set of properties per virtualhost, including `servername` (required), `documentroot` (required), `allow_override` (optional: defaults to the value of `apache_allow_override`), `options` (optional: defaults to the value of `apache_options`), `serveradmin` (optional), `serveralias` (optional) and `extra_parameters` (optional: you can add whatever additional configuration lines you'd like in here).
Here's an example using `extra_parameters` to add a RewriteRule to redirect all requests to the `www.` site:
```yaml
- servername: "www.local.dev"
serveralias: "local.dev"
documentroot: "/var/www/html"
extra_parameters: |
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
```
The `|` denotes a multiline scalar block in YAML, so newlines are preserved in the resulting configuration file output.
```yaml
apache_vhosts_ssl: []
```
No SSL vhosts are configured by default, but you can add them using the same pattern as `apache_vhosts`, with a few additional directives, like the following example:
```yaml
apache_vhosts_ssl:
- servername: "local.dev"
documentroot: "/var/www/html"
certificate_file: "/home/vagrant/example.crt"
certificate_key_file: "/home/vagrant/example.key"
certificate_chain_file: "/path/to/certificate_chain.crt"
extra_parameters: |
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
```
Other SSL directives can be managed with other SSL-related role variables.
```yaml
apache_ssl_no_log: true
```
Whether to print SSL-related task output to the console when running the playbook.
```yaml
apache_ssl_protocol: "All -SSLv2 -SSLv3"
apache_ssl_cipher_suite: "AES256+EECDH:AES256+EDH"
```
The SSL protocols and cipher suites that are used/allowed when clients make secure connections to your server. These are secure/sane defaults, but for maximum security, performand, and/or compatibility, you may need to adjust these settings.
```yaml
apache_allow_override: "All"
apache_options: "-Indexes +FollowSymLinks"
```
The default values for the `AllowOverride` and `Options` directives for the `documentroot` directory of each vhost. A vhost can overwrite these values by specifying `allow_override` or `options`.
```yaml
apache_mods_enabled:
- rewrite
- ssl
apache_mods_disabled: []
```
Which Apache mods to enable or disable (these will be symlinked into the appropriate location). See the `mods-available` directory inside the apache configuration directory (`/etc/apache2/mods-available` on Debian/Ubuntu) for all the available mods.
```yaml
apache_packages:
- [platform-specific]
```
The list of packages to be installed. This defaults to a set of platform-specific packages for RedHat or Debian-based systems (see `vars/RedHat.yml` and `vars/Debian.yml` for the default values).
```yaml
apache_state: started
```
Set initial Apache daemon state to be enforced when this role is run. This should generally remain `started`, but you can set it to `stopped` if you need to fix the Apache config during a playbook run or otherwise would not like Apache started at the time this role is run.
```yaml
apache_enabled: yes
```
Set the Apache service boot time status. This should generally remain `yes`, but you can set it to `no` if you need to run Ansible while leaving the service disabled.
```yaml
apache_packages_state: present
```
If you have enabled any additional repositories such as _ondrej/apache2_, [geerlingguy.repo-epel](https://github.com/geerlingguy/ansible-role-repo-epel), or [geerlingguy.repo-remi](https://github.com/geerlingguy/ansible-role-repo-remi), you may want an easy way to upgrade versions. You can set this to `latest` (combined with `apache_enablerepo` on RHEL) and can directly upgrade to a different Apache version from a different repo (instead of uninstalling and reinstalling Apache).
```yaml
apache_ignore_missing_ssl_certificate: true
```
If you would like to only create SSL vhosts when the vhost certificate is present (e.g. when using Lets Encrypt), set `apache_ignore_missing_ssl_certificate` to `false`. When doing this, you might need to run your playbook more than once so all the vhosts are configured (if another part of the playbook generates the SSL certificates).
## .htaccess-based Basic Authorization
If you require Basic Auth support, you can add it either through a custom template, or by adding `extra_parameters` to a VirtualHost configuration, like so:
```yaml
extra_parameters: |
<Directory "/var/www/password-protected-directory">
Require valid-user
AuthType Basic
AuthName "Please authenticate"
AuthUserFile /var/www/password-protected-directory/.htpasswd
</Directory>
```
To password protect everything within a VirtualHost directive, use the `Location` block instead of `Directory`:
```
<Location "/">
Require valid-user
....
</Location>
```
You would need to generate/upload your own `.htpasswd` file in your own playbook. There may be other roles that support this functionality in a more integrated way.
## Dependencies
None.
## Example Playbook
```yaml
- hosts: webservers
vars_files:
- vars/main.yml
roles:
- { role: geerlingguy.apache }
```
*Inside `vars/main.yml`*:
```yaml
apache_listen_port: 8080
apache_vhosts:
- {servername: "example.com", documentroot: "/var/www/vhosts/example_com"}
```
## License
MIT / BSD
## Author Information
This role was created in 2014 by [Jeff Geerling](https://www.jeffgeerling.com/), author of [Ansible for DevOps](https://www.ansiblefordevops.com/).

View file

@ -0,0 +1,62 @@
---
apache_enablerepo: ""
apache_listen_ip: "*"
apache_listen_port: 80
apache_listen_port_ssl: 443
apache_create_vhosts: true
apache_vhosts_filename: "vhosts.conf"
apache_vhosts_template: "vhosts.conf.j2"
# On Debian/Ubuntu, a default virtualhost is included in Apache's configuration.
# Set this to `true` to remove that default.
apache_remove_default_vhost: false
apache_global_vhost_settings: |
DirectoryIndex index.php index.html
apache_vhosts:
# Additional properties:
# 'serveradmin, serveralias, allow_override, options, extra_parameters'.
- servername: "local.dev"
documentroot: "/var/www/html"
apache_allow_override: "All"
apache_options: "-Indexes +FollowSymLinks"
apache_vhosts_ssl: []
# Additional properties:
# 'serveradmin, serveralias, allow_override, options, extra_parameters'.
# - servername: "local.dev",
# documentroot: "/var/www/html",
# certificate_file: "/path/to/certificate.crt",
# certificate_key_file: "/path/to/certificate.key",
# # Optional.
# certificate_chain_file: "/path/to/certificate_chain.crt"
apache_ignore_missing_ssl_certificate: true
apache_ssl_no_log: true
apache_ssl_protocol: "All -SSLv2 -SSLv3"
apache_ssl_cipher_suite: "AES256+EECDH:AES256+EDH"
# Only used on Debian/Ubuntu/Redhat.
apache_mods_enabled:
- rewrite
- ssl
apache_mods_disabled: []
# Set initial apache state. Recommended values: `started` or `stopped`
apache_state: started
# Set initial apache service status. Recommended values: `true` or `false`
apache_enabled: true
# Set apache state when configuration changes are made. Recommended values:
# `restarted` or `reloaded`
apache_restart_state: restarted
# Apache package state; use `present` to make sure it's installed, or `latest`
# if you want to upgrade or switch versions using a new repo.
apache_packages_state: present

View file

@ -0,0 +1,5 @@
---
- name: restart apache
service:
name: "{{ apache_service }}"
state: "{{ apache_restart_state }}"

View file

@ -0,0 +1,2 @@
install_date: Sun Feb 23 19:19:22 2025
version: 4.0.0

View file

@ -0,0 +1,36 @@
---
dependencies: []
galaxy_info:
role_name: apache
author: geerlingguy
description: Apache 2.x for Linux.
company: "Midwestern Mac, LLC"
license: "license (BSD, MIT)"
min_ansible_version: 2.10
platforms:
- name: Fedora
versions:
- all
- name: Amazon
versions:
- all
- name: Debian
versions:
- all
- name: Ubuntu
versions:
- trusty
- xenial
- bionic
- name: Solaris
versions:
- 11.3
galaxy_tags:
- web
- apache
- webserver
- html
- httpd
allow_duplicates: true

View file

@ -0,0 +1,21 @@
---
- name: Converge
hosts: all
become: true
vars:
apache_listen_port_ssl: 443
apache_create_vhosts: true
apache_vhosts_filename: "vhosts.conf"
apache_vhosts:
- servername: "example.com"
documentroot: "/var/www/vhosts/example_com"
pre_tasks:
- name: Update apt cache.
apt: update_cache=yes cache_valid_time=600
when: ansible_os_family == 'Debian'
changed_when: false
roles:
- role: geerlingguy.apache

View file

@ -0,0 +1,21 @@
---
role_name_check: 1
dependency:
name: galaxy
options:
ignore-errors: true
driver:
name: docker
platforms:
- name: instance
image: "geerlingguy/docker-${MOLECULE_DISTRO:-rockylinux8}-ansible:latest"
command: ${MOLECULE_DOCKER_COMMAND:-""}
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
privileged: true
pre_build_image: true
provisioner:
name: ansible
playbooks:
converge: ${MOLECULE_PLAYBOOK:-converge.yml}

View file

@ -0,0 +1,59 @@
---
- name: Configure Apache.
lineinfile:
dest: "{{ apache_server_root }}/ports.conf"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
mode: 0644
with_items: "{{ apache_ports_configuration_items }}"
notify: restart apache
- name: Enable Apache mods.
file:
src: "{{ apache_server_root }}/mods-available/{{ item }}.load"
dest: "{{ apache_server_root }}/mods-enabled/{{ item }}.load"
state: link
mode: 0644
with_items: "{{ apache_mods_enabled }}"
notify: restart apache
- name: Disable Apache mods.
file:
path: "{{ apache_server_root }}/mods-enabled/{{ item }}.load"
state: absent
with_items: "{{ apache_mods_disabled }}"
notify: restart apache
- name: Check whether certificates defined in vhosts exist.
stat: "path={{ item.certificate_file }}"
register: apache_ssl_certificates
with_items: "{{ apache_vhosts_ssl }}"
no_log: "{{ apache_ssl_no_log }}"
- name: Add apache vhosts configuration.
template:
src: "{{ apache_vhosts_template }}"
dest: "{{ apache_conf_path }}/sites-available/{{ apache_vhosts_filename }}"
owner: root
group: root
mode: 0644
notify: restart apache
when: apache_create_vhosts | bool
- name: Add vhost symlink in sites-enabled.
file:
src: "{{ apache_conf_path }}/sites-available/{{ apache_vhosts_filename }}"
dest: "{{ apache_conf_path }}/sites-enabled/{{ apache_vhosts_filename }}"
state: link
mode: 0644
force: "{{ ansible_check_mode }}"
notify: restart apache
when: apache_create_vhosts | bool
- name: Remove default vhost in sites-enabled.
file:
path: "{{ apache_conf_path }}/sites-enabled/{{ apache_default_vhost_filename }}"
state: absent
notify: restart apache
when: apache_remove_default_vhost

View file

@ -0,0 +1,54 @@
---
- name: Configure Apache.
lineinfile:
dest: "{{ apache_server_root }}/conf/{{ apache_daemon }}.conf"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
mode: 0644
with_items: "{{ apache_ports_configuration_items }}"
notify: restart apache
- name: Check whether certificates defined in vhosts exist.
stat: path={{ item.certificate_file }}
register: apache_ssl_certificates
with_items: "{{ apache_vhosts_ssl }}"
no_log: "{{ apache_ssl_no_log }}"
- name: Enable Apache mods.
copy:
dest: "{{ apache_server_root }}/conf.modules.d/99-ansible-{{ item }}.conf"
content: |
LoadModule {{ item }}_module modules/mod_{{ item }}.so
mode: 0644
with_items: "{{ apache_mods_enabled }}"
notify: restart apache
- name: Disable Apache mods
file:
path: "{{ apache_server_root }}/conf.modules.d/99-ansible-{{ item }}.conf"
state: absent
with_items: "{{ apache_mods_disabled }}"
notify: restart apache
- name: Add apache vhosts configuration.
template:
src: "{{ apache_vhosts_template }}"
dest: "{{ apache_conf_path }}/{{ apache_vhosts_filename }}"
owner: root
group: root
mode: 0644
notify: restart apache
when: apache_create_vhosts | bool
- name: Check if localhost cert exists (RHEL 8 and later).
stat:
path: /etc/pki/tls/certs/localhost.crt
register: localhost_cert
when: ansible_distribution_major_version | int >= 8
- name: Ensure httpd certs are installed (RHEL 8 and later).
command: /usr/libexec/httpd-ssl-gencerts
when:
- ansible_distribution_major_version | int >= 8
- not localhost_cert.stat.exists

View file

@ -0,0 +1,20 @@
---
- name: Configure Apache.
lineinfile:
dest: "{{ apache_server_root }}/{{ apache_daemon }}.conf"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
mode: 0644
with_items: "{{ apache_ports_configuration_items }}"
notify: restart apache
- name: Add apache vhosts configuration.
template:
src: "{{ apache_vhosts_template }}"
dest: "{{ apache_conf_path }}/{{ apache_vhosts_filename }}"
owner: root
group: root
mode: 0644
notify: restart apache
when: apache_create_vhosts | bool

View file

@ -0,0 +1,26 @@
---
- name: Configure Apache.
lineinfile:
dest: "{{ apache_server_root }}/listen.conf"
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
mode: 0644
with_items: "{{ apache_ports_configuration_items }}"
notify: restart apache
- name: Check whether certificates defined in vhosts exist.
stat: path={{ item.certificate_file }}
register: apache_ssl_certificates
with_items: "{{ apache_vhosts_ssl }}"
no_log: "{{ apache_ssl_no_log }}"
- name: Add apache vhosts configuration.
template:
src: "{{ apache_vhosts_template }}"
dest: "{{ apache_conf_path }}/{{ apache_vhosts_filename }}"
owner: root
group: root
mode: 0644
notify: restart apache
when: apache_create_vhosts | bool

View file

@ -0,0 +1,47 @@
---
# Include variables and define needed variables.
- name: Include OS-specific variables.
include_vars: "{{ ansible_os_family }}.yml"
- name: Include variables for Amazon Linux.
include_vars: "AmazonLinux.yml"
when:
- ansible_distribution == "Amazon"
- ansible_distribution_major_version == "NA"
- name: Define apache_packages.
set_fact:
apache_packages: "{{ __apache_packages | list }}"
when: apache_packages is not defined
# Setup/install tasks.
- include_tasks: "setup-{{ ansible_os_family }}.yml"
# Figure out what version of Apache is installed.
- name: Get installed version of Apache.
command: "{{ apache_daemon_path }}{{ apache_daemon }} -v"
changed_when: false
check_mode: false
register: _apache_version
- name: Create apache_version variable.
set_fact:
apache_version: "{{ _apache_version.stdout.split()[2].split('/')[1] }}"
- name: Include Apache 2.2 variables.
include_vars: apache-22.yml
when: "apache_version.split('.')[1] == '2'"
- name: Include Apache 2.4 variables.
include_vars: apache-24.yml
when: "apache_version.split('.')[1] == '4'"
# Configure Apache.
- name: Configure Apache.
include_tasks: "configure-{{ ansible_os_family }}.yml"
- name: Ensure Apache has selected state and enabled on boot.
service:
name: "{{ apache_service }}"
state: "{{ apache_state }}"
enabled: "{{ apache_enabled }}"

View file

@ -0,0 +1,6 @@
---
- name: Update apt cache.
apt: update_cache=yes cache_valid_time=3600
- name: Ensure Apache is installed on Debian.
apt: "name={{ apache_packages }} state={{ apache_packages_state }}"

View file

@ -0,0 +1,6 @@
---
- name: Ensure Apache is installed on RHEL.
package:
name: "{{ apache_packages }}"
state: "{{ apache_packages_state }}"
enablerepo: "{{ apache_enablerepo | default(omit, true) }}"

View file

@ -0,0 +1,5 @@
---
- name: Ensure Apache is installed on Solaris.
pkg5:
name: "{{ apache_packages }}"
state: "{{ apache_packages_state }}"

View file

@ -0,0 +1,5 @@
---
- name: Ensure Apache is installed on Suse.
zypper:
name: "{{ apache_packages }}"
state: "{{ apache_packages_state }}"

View file

@ -0,0 +1,82 @@
{{ apache_global_vhost_settings }}
{# Set up VirtualHosts #}
{% for vhost in apache_vhosts %}
<VirtualHost {{ apache_listen_ip }}:{{ apache_listen_port }}>
ServerName {{ vhost.servername }}
{% if vhost.serveralias is defined %}
ServerAlias {{ vhost.serveralias }}
{% endif %}
{% if vhost.documentroot is defined %}
DocumentRoot "{{ vhost.documentroot }}"
{% endif %}
{% if vhost.serveradmin is defined %}
ServerAdmin {{ vhost.serveradmin }}
{% endif %}
{% if vhost.documentroot is defined %}
<Directory "{{ vhost.documentroot }}">
AllowOverride {{ vhost.allow_override | default(apache_allow_override) }}
Options {{ vhost.options | default(apache_options) }}
{% if apache_vhosts_version == "2.2" %}
Order allow,deny
Allow from all
{% else %}
Require all granted
{% endif %}
</Directory>
{% endif %}
{% if vhost.extra_parameters is defined %}
{{ vhost.extra_parameters | indent(width=2, first=True) }}
{% endif %}
</VirtualHost>
{% endfor %}
{# Set up SSL VirtualHosts #}
{% for vhost in apache_vhosts_ssl %}
{% if apache_ignore_missing_ssl_certificate or apache_ssl_certificates.results[loop.index0].stat.exists %}
<VirtualHost {{ apache_listen_ip }}:{{ apache_listen_port_ssl }}>
ServerName {{ vhost.servername }}
{% if vhost.serveralias is defined %}
ServerAlias {{ vhost.serveralias }}
{% endif %}
{% if vhost.documentroot is defined %}
DocumentRoot "{{ vhost.documentroot }}"
{% endif %}
SSLEngine on
SSLCipherSuite {{ apache_ssl_cipher_suite }}
SSLProtocol {{ apache_ssl_protocol }}
SSLHonorCipherOrder On
{% if apache_vhosts_version == "2.4" %}
SSLCompression off
{% endif %}
SSLCertificateFile {{ vhost.certificate_file }}
SSLCertificateKeyFile {{ vhost.certificate_key_file }}
{% if vhost.certificate_chain_file is defined %}
SSLCertificateChainFile {{ vhost.certificate_chain_file }}
{% endif %}
{% if vhost.serveradmin is defined %}
ServerAdmin {{ vhost.serveradmin }}
{% endif %}
{% if vhost.documentroot is defined %}
<Directory "{{ vhost.documentroot }}">
AllowOverride {{ vhost.allow_override | default(apache_allow_override) }}
Options {{ vhost.options | default(apache_options) }}
{% if apache_vhosts_version == "2.2" %}
Order allow,deny
Allow from all
{% else %}
Require all granted
{% endif %}
</Directory>
{% endif %}
{% if vhost.extra_parameters is defined %}
{{ vhost.extra_parameters | indent(width=2, first=True) }}
{% endif %}
</VirtualHost>
{% endif %}
{% endfor %}

View file

@ -0,0 +1,18 @@
---
apache_service: httpd
apache_daemon: httpd
apache_daemon_path: /usr/sbin/
apache_server_root: /etc/httpd
apache_conf_path: /etc/httpd/conf.d
apache_vhosts_version: "2.4"
__apache_packages:
- httpd24
- httpd24-devel
- mod24_ssl
- openssh
apache_ports_configuration_items:
- regexp: "^Listen "
line: "Listen {{ apache_listen_port }}"

View file

@ -0,0 +1,14 @@
---
apache_service: apache2
apache_daemon: apache2
apache_daemon_path: /usr/sbin/
apache_server_root: /etc/apache2
apache_conf_path: /etc/apache2
__apache_packages:
- apache2
- apache2-utils
apache_ports_configuration_items:
- regexp: "^Listen "
line: "Listen {{ apache_listen_port }}"

View file

@ -0,0 +1,20 @@
---
apache_service: httpd
apache_daemon: httpd
apache_daemon_path: /usr/sbin/
apache_server_root: /etc/httpd
apache_conf_path: /etc/httpd/conf.d
apache_vhosts_version: "2.2"
__apache_packages:
- httpd
- httpd-devel
- mod_ssl
- openssh
apache_ports_configuration_items:
- regexp: "^Listen "
line: "Listen {{ apache_listen_port }}"
- regexp: "^#?NameVirtualHost "
line: "NameVirtualHost {{ apache_listen_ip }}:{{ apache_listen_port }}"

View file

@ -0,0 +1,19 @@
---
apache_service: apache24
apache_daemon: httpd
apache_daemon_path: /usr/apache2/2.4/bin/
apache_server_root: /etc/apache2/2.4/
apache_conf_path: /etc/apache2/2.4/conf.d
apache_vhosts_version: "2.2"
__apache_packages:
- web/server/apache-24
- web/server/apache-24/module/apache-ssl
- web/server/apache-24/module/apache-security
apache_ports_configuration_items:
- regexp: "^Listen "
line: "Listen {{ apache_listen_port }}"
- regexp: "^#?NameVirtualHost "
line: "NameVirtualHost {{ apache_listen_ip }}:{{ apache_listen_port }}"

View file

@ -0,0 +1,18 @@
---
apache_service: apache2
apache_daemon: httpd2
apache_daemon_path: /usr/sbin/
apache_server_root: /etc/apache2
apache_conf_path: /etc/apache2/conf.d
apache_vhosts_version: "2.2"
__apache_packages:
- apache2
- openssh
apache_ports_configuration_items:
- regexp: "^Listen "
line: "Listen {{ apache_listen_port }}"
- regexp: "^#?NameVirtualHost "
line: "NameVirtualHost {{ apache_listen_ip }}:{{ apache_listen_port }}"

View file

@ -0,0 +1,12 @@
---
apache_vhosts_version: "2.2"
apache_default_vhost_filename: 000-default
apache_ports_configuration_items:
- {
regexp: "^Listen ",
line: "Listen {{ apache_listen_port }}"
}
- {
regexp: "^#?NameVirtualHost ",
line: "NameVirtualHost {{ apache_listen_ip }}:{{ apache_listen_port }}"
}

View file

@ -0,0 +1,8 @@
---
apache_vhosts_version: "2.4"
apache_default_vhost_filename: 000-default.conf
apache_ports_configuration_items:
- {
regexp: "^Listen ",
line: "Listen {{ (apache_listen_ip == '*') | ternary('', apache_listen_ip + ':') }}{{ apache_listen_port }}"
}

View file

@ -0,0 +1,2 @@
.DS_Store
.dropbox

View file

@ -0,0 +1,26 @@
BSD 3-Clause License ("BSD License 2.0", "Revised BSD License", "New BSD License", or "Modified BSD License")
Copyright (c) 2019, SEMU Consulting
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,66 @@
Role Name
=========
## THIS REPO IS NO LONGER BEING ACTIVELY MAINTAINED OR SUPPORTED.
### IF ANYONE ELSE WANTS TO TAKE ON THE MAINTENANCE AND SUPPORT, FEEL FREE TO FORK IT.
[Ansible role](https://galaxy.ansible.com/semuadmin/webmin) to deploy Webmin web-based linux administration utility, running as a
systemd service.
Webmin service will be available on https://hostip:10000.
Default login will be the userid and password of the installer user.
You may get a browser warning about Webmin's default self-sign SSL certificate.
System will reboot after installation.
Requirements
------------
- Installation requires sudo privileges.
- Systemd for services control.
- Firewalld for firewall control (if required).
- Python for Ansible provisioning (note that some minimal distributions do not include python out of the box).
Role Variables
--------------
- `install_utilities`: false. Set to True to install various utility packages used by Webmin management functions (wget, git, ntpdate, sntp, smartmontools).
Note that some minimal distributions do not support all these tools out of the box and may require interactive installation.
- `enable_firewalld`: false. Set to True to open port 10000 via firewalld (assumes firewalld is installed and running).
- `uninstall_webmin` : false. Set to true to uninstall Webmin.
Dependencies
------------
None.
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
```yaml
- name: Provision webmin role
hosts: all
become: true
become_user: root
vars:
enable_firewalld: true
install_utilities: true
roles:
- semuadmin.webmin
```
License
-------
BSD 3-Clause

View file

@ -0,0 +1,15 @@
---
# defaults file for webmin
webmin_dir: /etc/webmin
webmin_yum_repo: "http://download.webmin.com/download/yum"
webmin_mirrorlist: "http://download.webmin.com/download/yum/mirrorlist"
webmin_gpgkey: "http://www.webmin.com/jcameron-key.asc"
webmin_apt_repo: "deb [signed-by=/etc/apt/trusted.gpg.d/jcameron-key.asc] https://download.webmin.com/download/repository sarge contrib"
enable_firewalld: false
install_utilities: false
uninstall_webmin: false
webmin_disable_reboot: false

View file

@ -0,0 +1,7 @@
---
# handlers file for webmin
- name: Restart webmin
ansible.builtin.systemd:
name: webmin
state: restarted

View file

@ -0,0 +1,2 @@
install_date: Sat Feb 22 17:36:07 2025
version: v1.0.9

View file

@ -0,0 +1,29 @@
galaxy_info:
role_name: webmin
author: semu
description: webmin role
company: SEMU Consulting
license: BSD 3-Clause
min_ansible_version: "7"
platforms:
- name: EL
versions:
- "9"
- "8"
- "7"
- name: Fedora
versions:
- "36"
- name: Debian
versions:
- bullseye
- name: Ubuntu
versions:
- focal
- bionic
- jammy
galaxy_tags:
- webmin

View file

@ -0,0 +1,10 @@
---
# tasks file for webmin #
- name: Install webmin
ansible.builtin.include_tasks: webmin.yml
when: not uninstall_webmin
- name: Uninstall webmin
ansible.builtin.include_tasks: uninstall.yml
when: uninstall_webmin

View file

@ -0,0 +1,42 @@
---
# tasks file for uninstall webmin #
- name: Remove Webmin files and directories
ansible.builtin.file:
path: "/etc/webmin"
state: absent
- name: Disable firewalld service.
ansible.posix.firewalld:
zone: public
service: webmin
permanent: true
state: disabled
immediate: true
when: enable_firewalld
- name: Remove yum repository for Redhat platforms
ansible.builtin.yum_repository:
name: webmin
description: Webmin yum repo
baseurl: "{{ webmin_yum_repo }}"
mirrorlist: "{{ webmin_mirrorlist }}"
state: absent
when: ansible_os_family == "RedHat"
- name: Remove apt repository for Debian platforms
ansible.builtin.apt_repository:
repo: "{{ webmin_apt_repo }}"
state: absent
when: ansible_os_family == "Debian"
- name: Unnstall supporting packages if added
ansible.builtin.package:
name:
- wget
- git
- ntpdate
- sntp
- smartmontools
state: absent
when: install_utilities

View file

@ -0,0 +1,94 @@
---
# tasks file for webmin#
- name: Install firewalld service template.
ansible.builtin.template:
src: webmin.xml.j2
dest: "/etc/firewalld/services/webmin.xml"
owner: root
group: root
mode: "0644"
when: enable_firewalld
- name: Reload firewalld to register new service.
ansible.builtin.command: firewall-cmd --reload
register: firewall
changed_when: "'success' in firewall.stdout"
when: enable_firewalld
- name: Enable firewalld service.
ansible.posix.firewalld:
zone: public
service: webmin
permanent: true
state: enabled
immediate: true
when: enable_firewalld
- name: Add yum repository and gpg key for Redhat platforms.
ansible.builtin.yum_repository:
name: webmin
description: Webmin yum repo
baseurl: "{{ webmin_yum_repo }}"
mirrorlist: "{{ webmin_mirrorlist }}"
gpgkey: "{{ webmin_gpgkey }}"
gpgcheck: true
state: present
when: ansible_os_family == "RedHat"
- name: Add a gpg key for Debian platforms.
ansible.builtin.get_url:
url: "{{ webmin_gpgkey }}"
dest: /etc/apt/trusted.gpg.d/jcameron-key.asc
owner: root
group: root
mode: "0644"
when: ansible_os_family == "Debian"
- name: Add apt repository for Debian platforms.
ansible.builtin.apt_repository:
repo: "{{ webmin_apt_repo }}"
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Install https transport for Debian platforms.
ansible.builtin.package:
name:
- apt-transport-https
state: present
when: ansible_os_family == "Debian"
- name: Install Webmin.
ansible.builtin.package:
name:
- webmin
state: present
- name: Install supporting packages if required.
ansible.builtin.package:
name:
- wget
- git
- ntpdate
- sntp
- smartmontools
state: present
when: install_utilities
- name: Remove old systemd service.
ansible.builtin.file:
path: /etc/systemd/system/webmin.service
state: absent
- name: Enable webmin as systemd service.
ansible.builtin.systemd:
state: started
enabled: true
daemon_reload: true
name: webmin
- name: Reboot machine.
ansible.builtin.reboot:
reboot_timeout: 3600
when: not webmin_disable_reboot

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>webmin</short>
<description>Webmin Web Based Administration</description>
<port port="10000" protocol="tcp"/>
</service>

View file

@ -0,0 +1,6 @@
---
- name: Test webmin role
hosts: localhost
remote_user: root
roles:
- webmin

View file

@ -0,0 +1,2 @@
---
# vars file for webmin

View file

@ -0,0 +1,49 @@
- name: webmin sys265
hosts: webmin
become: true
vars:
install_utilities: false
firewalld_enable: true
pre_tasks:
- name: add webmin repo and GPG key
yum_repository:
name: webmin
description: Webmin Distribution Neutral
baseurl: http://download.webmin.com/download/yum
enabled: true
gpgcheck: true
gpgkey: http://www.webmin.com/jcameron-key.asc
- name: clean and update YUM cache
yum:
update_cache: yes
roles:
- semuadmin.webmin
handlers:
- name: reload firewall
command: firewall-cmd --reload
tasks:
- name: add firewall rule
firewalld:
port: 10000/tcp
permanent: true
state: enabled
notify: reload firewall
- name: install webmin
yum:
name: webmin
state: present
- name: enable and start webmin service
systemd:
name: webmin
enabled: true
state: started
daemon_reload: yes

View file

@ -0,0 +1,10 @@
- name: install windows applications
hosts: windows
tasks:
- name: install firefox and 7zip
win_chocolatey:
name:
- firefox
- 7zip
- notepadplusplus
state: present

View file

@ -0,0 +1,14 @@
# This is the network config written by 'subiquity'
network:
ethernets:
ens160:
dhcp4: no
addresses:
- 10.0.5.12/24
routes:
- to: default
via: 10.0.5.2
nameservers:
addresses:
- 10.0.5.5
version: 2

View file

@ -0,0 +1 @@
docker-01 configuration

View file

@ -0,0 +1,142 @@
# The top level settings are used as module
# and system configuration.
# A set of users which may be applied and/or used by various modules
# when a 'default' entry is found it will reference the 'default_user'
# from the distro configuration specified below
users:
- default
# If this is set, 'root' will not be able to ssh in and they
# will get a message to login instead as the default $user
disable_root: true
# This will cause the set+update hostname module to not operate (if true)
preserve_hostname: true
hostname: docker01-charlotte
fqdn: docker01-charlotte.charlotte.local
# If you use datasource_list array, keep array items in a single line.
# If you use multi line array, ds-identify script won't read array items.
# Example datasource config
# datasource:
# Ec2:
# metadata_urls: [ 'blah.com' ]
# timeout: 5 # (defaults to 50 seconds)
# max_wait: 10 # (defaults to 120 seconds)
# The modules that run in the 'init' stage
cloud_init_modules:
- migrator
- seed_random
- bootcmd
- write-files
- growpart
- resizefs
- disk_setup
- mounts
- set_hostname
- update_hostname
- update_etc_hosts
- ca-certs
- rsyslog
- users-groups
- ssh
# The modules that run in the 'config' stage
cloud_config_modules:
# Emit the cloud config ready event
# this can be used by upstart jobs for 'start on cloud-config'.
- emit_upstart
- snap
- ssh-import-id
- keyboard
- locale
- set-passwords
- grub-dpkg
- apt-pipelining
- apt-configure
- ubuntu-advantage
- ntp
- timezone
- disable-ec2-metadata
- runcmd
- byobu
# The modules that run in the 'final' stage
cloud_final_modules:
- package-update-upgrade-install
- fan
- landscape
- lxd
- ubuntu-drivers
- write-files-deferred
- puppet
- chef
- mcollective
- salt-minion
- reset_rmc
- refresh_rmc_and_interface
- rightscale_userdata
- scripts-vendor
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
- scripts-user
- ssh-authkey-fingerprints
- keys-to-console
- install-hotplug
- phone-home
- final-message
- power-state-change
# System and/or distro specific settings
# (not accessible to handlers/transforms)
system_info:
# This will affect which distro class gets used
distro: ubuntu
# Default user name + that default users groups (if added/used)
default_user:
name: ubuntu
lock_passwd: True
gecos: Ubuntu
groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/bash
network:
renderers: ['netplan', 'eni', 'sysconfig']
# Automatically discover the best ntp_client
ntp_client: auto
# Other config here will be given to the distro class and/or path classes
paths:
cloud_dir: /var/lib/cloud/
templates_dir: /etc/cloud/templates/
upstart_dir: /etc/init/
package_mirrors:
- arches: [i386, amd64]
failsafe:
primary: http://archive.ubuntu.com/ubuntu
security: http://security.ubuntu.com/ubuntu
search:
primary:
- http://%(ec2_region)s.ec2.archive.ubuntu.com/ubuntu/
- http://%(availability_zone)s.clouds.archive.ubuntu.com/ubuntu/
- http://%(region)s.clouds.archive.ubuntu.com/ubuntu/
security: []
- arches: [arm64, armel, armhf]
failsafe:
primary: http://ports.ubuntu.com/ubuntu-ports
security: http://ports.ubuntu.com/ubuntu-ports
search:
primary:
- http://%(ec2_region)s.ec2.ports.ubuntu.com/ubuntu-ports/
- http://%(availability_zone)s.clouds.ports.ubuntu.com/ubuntu-ports/
- http://%(region)s.clouds.ports.ubuntu.com/ubuntu-ports/
security: []
- arches: [default]
failsafe:
primary: http://ports.ubuntu.com/ubuntu-ports
security: http://ports.ubuntu.com/ubuntu-ports
ssh_svcname: ssh

View file

@ -0,0 +1,9 @@
127.0.0.1 localhost
127.0.1.1 docker01-charlotte
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

View file

@ -0,0 +1 @@
mgmt01-charlotte

View file

@ -0,0 +1,15 @@
# use this version of python
FROM python:3.12-slim
# create a working directory and copy requirements file to it
WORKDIR /app
COPY app/requirements.txt /app/requirements.txt
# install dependencies
RUN pip install --no-cache-dir -r requirements.txt
# copy the rest of the files to working directory
COPY app /app
# run the python script when the container starts
CMD ["python", "app.py"]

View file

@ -0,0 +1,143 @@
# SYS265 - Mini Docker Project
flask web-chat app with docker
___
>[!Note]
> I've been learning some network programming lately, so most of the python is my own. but I did use AI for the Dockerfile, some of the javascript, and general troubleshooting (netwoking in a Docker container can get confusing)
## Project Structure
```
├── docker-chat
│   ├── app
│   │   ├── app.py
│   │   ├── requirements.txt
│   │   └── templates
│   │   └── index.html
│   ├── docker-compose.yml
│   └── Dockerfile
```
___
## 1. create [app.py](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-ii-sys265/docker_proj1/app/app.py)
this is the python/flask backend for the web app. it will open a websocket on port 5000 and handle message sent over it.
```
from flask import Flask, render_template
from flask_socketio import SocketIO, send
# initialize flask and socketio
app = Flask(__name__)
socketio = SocketIO(app)
# default page
@app.route('/')
def index():
return render_template('index.html')
# runs when message is received on socket
@socketio.on('message')
def handle_message(msg):
print("message: " + msg)
send(msg, broadcast=True)
# open websocket, listen on port 5000
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=5000, allow_unsafe_werkzeug=True)
```
## 2. create [index.html](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-ii-sys265/docker_proj1/app/templates/index.html)
this is the html frontend for the web page, as well as some javascript to be a medium between network connections and the frontend webpage
```
<!DOCTYPE html>
<html>
<head>
<title>sys265 chat</title>
</head>
<body>
<ul id="messages"></ul>
<input id="message_input" type="text">
<button onclick="sendMessage()">send</button>
<!-- import javascript sockets.io library-->
<script src="https://cdn.socket.io/4.0.1/socket.io.min.js"></script>
<script>
// create websocket object
const socket = io()
// update html when a message is sent/received
socket.on('message', function(msg) {
let li = document.createElement('li');
li.textContent = msg;
document.getElementById('messages').appendChild(li);
});
// send message on socket when button is clicked
function sendMessage() {
const message = document.getElementById('message_input').value;
socket.send(message);
document.getElementById('message_input').value = '';
}
</script>
</body>
</html>
```
## 3. create [requirements.txt](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-ii-sys265/docker_proj1/app/requirements.txt)
this includes necessary dependencies. they will be installed via Dockerfile
```
Flask==2.2.2
flask-socketio==5.3.2
werkzeug==2.2.2
```
## 4. create [docker-compose.yml](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-ii-sys265/docker_proj1/docker-compose.yml)
this defines the services to be used. while this could work without the chat-net network, creating an isolated network made setting this up simpley imo, especially since we are already running wordpress.
```
version: '3.8'
services:
chat-server:
build: .
ports:
- "5000:5000"
volumes:
- ./app:/app
networks:
- chat-net
networks:
chat-net:
driver: bridge
```
## 5. create [Dockerfile](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-ii-sys265/docker_proj1/Dockerfile)
```
# use this version of python
FROM python:3.12-slim
# create a working directory and copy requirements file to it
WORKDIR /app
COPY app/requirements.txt /app/requirements.txt
# install dependencies
RUN pip install --no-cache-dir -r requirements.txt
# copy the rest of the files to working directory
COPY app /app
# run the python script when the container starts
CMD ["python", "app.py"]
```
## 6. run docker-compose
```
cd docker-chat
docker-compose up -d
```
![image](../../assets/5e739863-3710-4ea0-8988-2a9c56ddb981.png)

View file

@ -0,0 +1,21 @@
from flask import Flask, render_template
from flask_socketio import SocketIO, send
# initialize flask and socketio
app = Flask(__name__)
socketio = SocketIO(app)
# default page
@app.route('/')
def index():
return render_template('index.html')
# runs when message is received on socket
@socketio.on('message')
def handle_message(msg):
print("message: " + msg)
send(msg, broadcast=True)
# open websocket, listen on port 5000
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=5000, allow_unsafe_werkzeug=True)

View file

@ -0,0 +1,3 @@
Flask==2.2.2
flask-socketio==5.3.2
werkzeug==2.2.2

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<title>sys265 chat</title>
</head>
<body>
<ul id="messages"></ul>
<input id="message_input" type="text">
<button onclick="sendMessage()">send</button>
<!-- import javascript sockets.io library-->
<script src="https://cdn.socket.io/4.0.1/socket.io.min.js"></script>
<script>
// create websocket object
const socket = io()
// update html when a message is sent/received
socket.on('message', function(msg) {
let li = document.createElement('li');
li.textContent = msg;
document.getElementById('messages').appendChild(li);
});
// send message on socket when button is clicked
function sendMessage() {
const message = document.getElementById('message_input').value;
socket.send(message);
document.getElementById('message_input').value = '';
}
</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
version: '3.8'
services:
chat-server:
build: .
ports:
- "5000:5000"
volumes:
- ./app:/app
networks:
- chat-net
networks:
chat-net:
driver: bridge

View file

@ -0,0 +1,51 @@
# Lab00 - Routing and Windows
Our goal is to build a realistic server environment consisting of a routed network (LAN and WAN) as well as introduce Server 2019 Desktop and Core and the systems required to manage them.
## FW01 and WKS01
- [use this doc](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-i-sys255/lab01-environment-setup.md), configuration is exactly the same
## AD01
- (admin password is `password123!`)
- `sconfig` \
![image](../assets/b42fc4c4-07fe-44e1-ae48-59a1ea275408.png)
- Invoke powershell and install Active Directory: `Install-WindowsFeature AD-Domain-Services -IncludeManagementTools` \
![image](../assets/2a087f38-8b59-4497-9162-1631205d0150.png)
- Install the Forest: `Install-ADDSForest -DomainName charlotte.local` \
![image](../assets/b295e94c-3da4-4dbe-98d5-45f25a4da00a.png)
- You should be in a domain now \
![image](../assets/73076712-88fa-4c39-866b-da138c52002d.png)
### creating domain users (one user, one admin):
- `net user charlotte.croce password123! /ADD /DOMAIN`
- `net user charlotte.croce-adm password123! /ADD /DOMAIN`
- `net group "Domain Admins" charlotte.croce-adm /ADD /DOMAIN`
## MGMT01
MGMT01 is a Server 2019 with GUI. Its job will be to remotely manage any server core systems.
password: `password123!` \
![image](../assets/b752ce4c-f831-4619-b563-9a2ff9eb57c5.png)
to join domain:
- `sconfig` -> 1 -> D -> charlotte.local -> Administrator -> type Administrator password in prompt -> restart
- login as the charlotte.croce-adm domain user
adding ad01 to management scope
- server manager - add roles and features
- add the following features: \
![image](../assets/25634b91-4a27-4ff5-a218-337fab157561.png)
![image](../assets/f1b9d632-2664-4209-beae-3ee167b93a76.png)
- create DNS records: [use this doc](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-i-sys255/lab02-dns%2Badds-role.md)
- note: it's easier to create the reverse lookup zone first, as PTR records will be created automatically when you create a new A record, although you will still have to manually create some PTRs
![image](../assets/1fc7982f-2d40-49d2-8264-356db5fb0d8c.png)
![image](../assets/d750c565-6a8c-4867-8da3-949046bb5a1e.png)
- finally, join wks01 to the domain
- before doing so, we must change the DNS server to 10.0.5.5, to recognize charlotte.local
![image](../assets/f7c0d739-296c-4fab-96b2-4afe4439aee6.png)

View file

@ -0,0 +1,63 @@
# lab01- Network Management
## nmon1-charlotte
- setup with hostname, username, networking (10.0.5.11, remember: add `charlotte.local` to search domain)
- add record to DNS manager \
![image](../assets/40d632c5-18c8-42b0-a938-19f6aabce1d0.png)
```
I had trouble reaching the internet on nmon1, then realized fw01 couldn't reach the internet as well.
idk what happened but I rebooted fw01 and it worked again
```
## enable SNMP services on pfSense
- web dashboard (10.0.5.2)
- services -> SNMP \
![image](../assets/27e9470d-e84b-4e8b-8076-cfcbc9b54dea.png) \
![image](../assets/bcdeb3dd-1245-4fc0-aff3-0a84cb383c8f.png)
- restart SNMP service \
![image](../assets/727824d9-510f-4235-8e62-7360a41ebae2.png)
## Install and Test SNMP Client on nmon01
- `sudo yum install net-snmp-utils` \
![image](../assets/c2924ebd-c975-4cbf-9b0e-b26e36954fdb.png)
## Install SNMPD (a SNMP Server) on web01
- set up web01 (10.0.5.12, you know the drill by now)
- `sudo yum install net-snmp-utils net-snmp`
- The default snmp configuration does not suit our purpose. Make a backup copy of /etc/snmp/snmpd.conf and create a new/blank version.
- `sudo cp /etc/snmp/snmpd.conf /etc/snmp/snmpd.conf.backup` \
![image](../assets/38e9d23f-a37a-4e61-948c-b949cbb19acc.png)
- allow 161/udp through firewall
```
sudo firewall-cmd --add-port=161/udp --permanent`
sudo firewall-cmd --reload`
```
- enable/start snmpd
```
sudo systemctl enable snmpd
sudo systemctl start snmpd
```
## install the SNMP Service Feature on AD01 using Server Manager on MGMT
## install the SNMP-Tools Remote Administration Feature on MGM01
![image](../assets/545f45bb-c125-4f69-9447-b605773f26be.png) \
![image](../assets/f62408cf-24bd-4947-9277-df5637f800e5.png)
## Enable Remote Management on AD01
Remote Computer Management does not work immediately for our remote AD01 Server due to firewall restrictions as seen in the error message. \
![image](../assets/f6c94f07-746a-4cc1-8f09-db5eb76f08a5.png) \
You will need to fix this by invoking a remote PowerShell session with AD01 from mgmt01. \
![image](../assets/b60a950e-bc09-424d-93cc-38c55deb0105.png)
## SNMP Service Security Properties on AD01
- Adjust the SNMP service properties on AD01 to add the SYS265 community string and limit queries to those from nmon01. \
![image](../assets/2629d201-965b-4a1e-8afe-7b88ebcbddd9.png)
- Restart the SNMP Service on ad01
## Capturing snmp packets nmon01->web01
- on web01: `tcpdump -i ens192 port 161 -c10 -AAA`
- on nom01: `snmpwalk -Os -c SYS265 -v2c web01-charlotte system`

View file

@ -0,0 +1,15 @@
# DHCP Lab
[reference from SYS255](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-i-sys255/lab08.5-configure-windows-dhcp-server.md)
ad01- add roles and features \
![image](../assets/57c507d3-202d-4f0b-a19e-3da3bf8f3450.png)
DNS Manager
Configurations:
- Scope: 10.0.5.150 - 10.0.5.175
- Subnet mask: /24
- Router: 10.0.5.2
- DNS: 10.0.5.5
on wks-01, set IP to acquire automatically \
![image](../assets/0dbd53ce-1e87-4aa7-8c4d-e592233d9f19.png)

View file

@ -0,0 +1,181 @@
# Containerization with Docker
![image](https://git.charlotte.sh/lotte/ChamplaintechJournals/src/branch/main/assets/7a571e73-76f3-4efe-a4dd-644c0c856011.png)
## set up docker01 - Ubuntu 20.04 cloud server
IP Address: 10.0.5.12 (change web01 address to 10.0.5.20) \
Default Gateway: 10.0.5.2 \
DNS: 10.0.5.5 \
![image](https://git.charlotte.sh/lotte/ChamplaintechJournals/src/branch/main/assets/e8491101-e466-4046-be31-eb397ee2f159.png)
### changing hostname. it is different on Ubuntu Cloud
- in `/etc/cloud/cloud.cfg`:
```
preserve_hostname: true
hostname: docker01-charlotte (add this line under)
fqdn: docker01-charlotte.charlotte.local (add this line under)
```
- change hostname for 127.0.1.1 in `/etc/hosts` file
![image](https://git.charlotte.sh/lotte/ChamplaintechJournals/src/branch/main/assets/c921d829-5bc4-4048-a4fb-de42b1f413a7.png)
- finally, `sudo hostnamectl hostname docker01-charlotte`
- update DNS records on mgmt01 (remember to change web01 record too)
## docker installation
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04
update and install prerequisite packages, this will let apt use packages over HTTPS
```
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common
```
add the GPG key
```
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
```
add docker repo to APT sources
```
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
```
validate installation is from docker repo. Notice that docker-ce is not installed,
but the candidate for installation is from the Docker repository for Ubuntu 20.04 (focal).
```
apt-cache policy docker-ce | head
```
![image](https://git.charlotte.sh/lotte/ChamplaintechJournals/src/branch/main/assets/bb0207b1-5010-4d36-9fdd-028ec450cc5e.png)
install docker
```
sudo apt install docker-ce
```
check status
```
sudo systemctl status docker
```
### executing the docker command without sudo:
add user to the docker group, apply the new group membership, and logout/log back in
```
sudo usermod -aG docker charlotte
su - charlotte
```
## using docker
### downloading images
search for images availabe on Docker Hub
```
docker search <image-name>
```
download from Dockuer Hub
```
docker pull <image-name>
```
see installed images
```
docker images
```
## docker-compose
- https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-compose-on-ubuntu-20-04
> "Docker Compose is a tool that allows you to run multi-container application environments based on definitions set in a YAML file."
download the 1.29.2 release and save the executable file at /usr/local/bin/docker-compose
```
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
```
make docker-compose executable:
```
sudo chmod +x /usr/local/bin/docker-compose
```
verify installation
```
docker-compose --version
```
The following command pulls down an Arch Linux based docker image, invokes it in a container, and runs /bin/echo "HELLO SYS265 SNOWY DAYS '' before deleting the container.
```
docker run --rm archlinux:latest /bin/echo "HELLO SYS265 SNOWY DAYS"
```
___
## docker run command syntax (example)
- e.g. The following command will pull down the image, application and dependencies associated with a simple python web application. `docker run -d -P training/webapp python app.py`
- `docker`: CLI for interacting with docker
- `run`: create and start a new container
- `-d` (or `--detach`): the container runs in the background.
- useful for non-interactive services, like webservers and databases
- `-P` (or `--publich-all`): automatically publishes all exposed ports of the container to random host ports.
- This allows external access to the services running in the container without having to specify port mappings manually.
- `training/webapp`: the docker image from which the container is created
- In this case, an image named `webapp` that is located in the `training` repository
- `python`: command that will be executed inside the container once it starts
- `app.py`: argument passed to the python command
- the Python script `app.py` should be executed by the Python interpreter when the container starts.
- `docker run httpd` will automatically set up an apache web server in the container
### to stop docker process
```
docker stop <container ID>
```
## dockerized WordPress
https://github.com/docker/awesome-compose/tree/master/wordpress-mysql
- create a directory `docker-wp`
- create compose.yml
>[!Caution]
> Absolutely never use a tab in a docker-compose.yml file
```
services:
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10.6.4-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8.0.27
command: '--default-authentication-plugin=mysql_native_password'
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
expose:
- 3306
- 33060
wordpress:
image: wordpress:latest
ports:
- 80:80
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
volumes:
db_data:
```
- `docker compose up -d`
- wait...it's really that easy?
- yes
___
### showing how containers use the same kernel as the host
- example: the following commands will:
- Print out the current version of Ubuntu on docker01. `cat /etc/lsb-release`
- Print out the current version of docker01's linux kernel. `echo "Current Kernel is: $(uname -a)"`
- Invoke a container of the stored Ubuntu image as well as an interactive bash command prompt, and print out the kernel being used by the Ubuntu container. `docker run -it archlinux /bin/uname -a`
![image](../assets/4df08b6e-cbf7-474b-8301-f2f52e65ba4d.png)
- as you can see, both the docker container(archlinux) and the host(docker01-charlotte) are using the same kernels

View file

@ -0,0 +1,59 @@
# Git and Linux SSH
>[!Note]
>This entry is pretty empty because I've already written [this journal Entry for using git/github](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/automation-sys320/week01/github_setup.md)
# Automating ssh authentication
- generate SSH key pair on your management node (in this case, web-01)
- push pubkey to github repo
- run the secure-ssh.sh script on remote host to create a new user that has the pubkey in `.../.ssh/authorized_keys`
- you can now ssh from web-01 to remote hosts without password!
___
### creating/adding ssh key
```
ssh-keygen -t rsa -b 4096 -C "sys265"
cat ~/.ssh/id_rsa
```
copy this to github SSH & GPG section
- to test: `ssh -T git@github.com`
- `git remote -v`
- if git is using https. you will have to change it to use ssh
- `git remote set-url origin git@github.com:charlottecroce/champlaintechjournals`
___
before being able to commit, you will have to add the following authentication:
- `git config user.email charlotte.croce@mymail.champlain.edu`
- `git config user.name charlottecroce`
## docker-01
copying config files to git repo
```
sudo apt install git
git clone https://git.charlotte.sh/lotte/ChamplainTechJournals
cd ~/champlaintechjournals/sysadmin-ii-sys265/configs/docker-01
sudo cp /etc/hosts .
sudo cp /etc/netplan/* .
sudo cp /etc/cloud/cloud.cfg .
```
## mgmt-01
- install git from web
```
git clone https://git.charlotte.sh/lotte/ChamplainTechJournals
cd ~/champlaintechjournals/sysadmin-ii-sys265/configs/mgmt-01
echo $(hostname) > README.md
git add .
git commit -m "added a readme"
git push
```
- login with token authentication
# web-01
- `sudo yum install git`
- create ssh key and connect to git with it (see above section)
```
mkdir -p linux/public-keys
mkdir -p linux/ubuntu
mkdir -p linux/centos7
```
- create [secure-ssh.sh script](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-ii-sys265/linux/centos7/secure-ssh.sh)

View file

@ -0,0 +1,322 @@
# Automation with Ansible
Demonisioning: web01, nmon-01, docker-01 😢
___
## New Machines
### controller-charlotte - Ubuntu
configure with netplan
```
network:
ethernets:
ens160:
dhcp4: no
addresses:
- 10.0.5.90/24
routes:
- to: default
via: 10.0.5.2
nameservers:
addresses:
- 10.0.5.5
version: 2
```
#### to reset DNS
```
dhclient -r
dhclient
```
### ansible1-charlotte - CentOS
configure with nmtui
- IP: 10.0.5.91
- DG: 10.0.5.2
- DNS: 10.0.5.5
### ansible2-charlotte - CentOS
configure with nmtui
- IP: 10.0.5.92
- DG: 10.0.5.2
- DNS: 10.0.5.5
## Initial Configuration
- on all machines, create a sudo account named deployer (use same password across all systems)
- install ansible on controller
```
sudo apt install ansible sshpass python3-paramiko
```
- Configure sudo access:
- create `/etc/sudoers.d/sys265` on all systems
- add the following line to allow passwordless sudo for deployer:
```
deployer ALL=(ALL) NOPASSWD:ALL
```
> [!Note]
> Although it is not uncommon to update `/etc/sudoers` directly, it is far easier to script the addition of a file to `/etc/sudoers.d`
## SSH Key Setup
As the deployer user on controller:
- Create RSA keypair with passphrase:
```
ssh-keygen -t rsa
```
- copy pukey to ansible1 and ansible2
```
ssh-copy-id deployer@ansible1-charlotte
ssh-copy-id deployer@ansible2-charlotte
```
-configure `ssh-agent` to avoid typing passphrase for 4 hours
```
eval(ssh-agent) # test to see if ssh-agent is running, and if not,run it
ssh-add -t 14400
```
## Ansible Configuration
in `deployer@controller:/home/deployer/`
- make directory structure
```
mkdir -p ansible/roles
cd ansible/
```
- create inventory and test conection
```
echo ansible1-charlotte >> inventory.txt
echo ansible2-charlotte >> inventory.txt
cat inventory.txt
```
```
ansible all -m ping -i inventory.txt
```
- add webmin tag to `inventory.txt` and test
```
ansible1-charlotte
[webmin]
ansible2-charlotte
```
```
deployer@controller-charlotte:~/ansible$ ansible webmin -m ping -i inventory.txt
ansible2-charlotte | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"ping": "pong"
}
```
## webmin installation
- install webmin role
```
ansible-galaxy install semuadmin.webmin -p roles/
```
- create `webmin.yml` playbook to handle repository setup, installation, and firewall configuration
```
- name: webmin sys265
hosts: webmin
become: true # Run all tasks with sudo/root privileges
vars:
install_utilities: false
firewalld_enable: true
pre_tasks: # before role execution. we need the repo/key before executing webmin installation role
- name: add webmin repo and GPG key
yum_repository:
name: webmin
description: Webmin Distribution Neutral
baseurl: http://download.webmin.com/download/yum
enabled: true
gpgcheck: true
gpgkey: http://www.webmin.com/jcameron-key.asc
# update YUM cache to recognize new repository
- name: clean and update YUM cache
yum:
update_cache: yes
roles:
- semuadmin.webmin # apply the webmin installation role
handlers: # will run when a task has notify:name parameter
- name: reload firewall # runs after adding firewall rule
command: firewall-cmd --reload
tasks:
# open port 10000 in firewall for webmin web interface
- name: add firewall rule
firewalld:
port: 10000/tcp
permanent: true
state: enabled
notify: reload firewall
- name: install webmin
yum:
name: webmin
state: present # will only install if not already
- name: enable and start webmin service
systemd:
name: webmin
enabled: true
state: started
daemon_reload: yes # reload systemd to recognize new service
```
- run playbook
```
ansible-playbook -i inventory.txt roles/webmin.yml
```
- change webmin root password
```
sudo /usr/libexec/webmin/changepass.pl /etc/webmin root newpassword
```
## apache isntallation
- edit inventory.txt
```
[apache]
ansible1-charlotte
[webmin]
ansible2-charlotte
```
- install apache role
```
ansible-galaxy install geerlingguy.apache -p roles/
```
- create `apache.yml` file
```
- name: apache sys265
hosts: apache
become: true # Run all tasks with sudo/root privileges
vars:
install_utilities: false
firewalld_enable: true
ansible_os_family: RedHat
ansible_distribution: CentOS # required because role searches for Rocky config files
roles:
- geerlingguy.apache # apply the apache installation role
handlers: # will run when a task has notify:name parameter
- name: reload firewall # runs after adding firewall rule
command: firewall-cmd --reload
tasks:
# open port 443 in firewall for apache web interface
- name: add firewall rule
firewalld:
port: "{{ item }}"
permanent: true
immediate: true
state: enabled
loop:
- 80/tcp
- 443/tcp
notify: reload firewall
- name: install apache
yum:
name: httpd
state: present # will only install if not already
- name: enable and start apache service
systemd:
name: httpd
enabled: true
state: started
daemon_reload: yes # reload systemd to recognize new service
```
- run playbook
```
ansible-playbook -i inventory.txt roles/webmin.yml
```
# Ansible on Windows
## OpenSSH Server Setup
>[!Caution]
> DO NOT INSTALL 32 BIT VERSION
### Install OpenSSH
Run these commands in PowerShell as Administrator:
```
wget https://github.com/PowerShell/Win32-OpenSSH/releases/download/v9.8.1.0p1-Preview/OpenSSH-Win64.zip -O 'C:\Program Files\OpenSSH.zip'
Expand-Archive -Path 'C:\Program Files\OpenSSH.zip' -DestinationPath 'C:\Program Files\OpenSSH'
rm 'C:\Program Files\OpenSSH.zip'
powershell.exe -ExecutionPolicy Bypass -File 'C:\Program Files\OpenSSH\OpenSSH-Win64\install-sshd.ps1'
```
### Configure OpenSSH
- start service
```
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
Get-Service -Name sshd # check if running
```
- add firewall rule
```
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
Get-NetFirewallRule | Where-Object DisplayName -Like '*ssh*'
```
- set PowerShell as default SSH shell
```
Set-ItemProperty "HKLM:\Software\Microsoft\Powershell\1\ShellIds" -Name ConsolePrompting -Value $true
New-ItemProperty -Path HKLM:\SOFTWARE\OpenSSH -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
```
- add `charlotte.croce-adm` to the **Remote Management Users** groups
- Add/uncomment the following lines in C:\ProgramData\ssh\sshd_config
- `StrictModes no` is sometimes needed on Windows systems because Windows permissions don't map perfectly to the UNIX-style permissions that OpenSSH expects
```
AllowUsers charlotte\charlotte.croce-adm
StrictModes no
```
## Ansible Setup
### Inventory Setup
- add windows machines to `inventory.txt`
```
[windows]
mgmt01-charlotte
wks01-charlotte
[windows:vars]
ansible_shell_type=powershell
```
- create ansible.cfg in ansible directory, to skip host key checking
```
[defaults]
host_key_checking = false
```
- test connection
```
ansible windows -i inventory.txt -m win_ping -u charlotte.croce-adm@charlotte.local --ask-pass
```
## Software deployment using win_chocolatey
- create playbook `roles/windows_software.yml`
```
- name: install windows applications
hosts: windows
tasks:
- name: install firefox and 7zip
win_chocolatey:
name:
- firefox
- 7zip
state: present
```
- run playbook
```
ansible-playbook -i inventory.txt roles/windows_software.yml -u charlotte.croce-adm@charlotte.local --ask-pass
```
- If you encounter .NET Framework errors, install version 4.8 (in my case I needed version 4.8, it will probably be a different version in the future)
```
Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=2088631" -OutFile "C:\dotNetFx48.exe"
Start-Process -FilePath "C:\dotNetFx48.exe" -ArgumentList "/quiet /norestart" -Wait
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" -Name Release # verify installation
```
> [!Note]
> Installation may take several minutes. System restart required after installation.
- list packages installed with chocolatey
```
'C:\ProgramData\chocolatey\bin\choco.exe' list
```

View file

@ -0,0 +1,69 @@
# AD Group Policy & SW Deployment
## Prepare an OU, user & workstation
Before we get into configuring a Group Policy Object (GPO) within Active Directory (AD), lets set the AD stage to deploy a software package. Via AD Users & Computers, create a “Test OU”.
![image](../../assets/a5a9d811-0e27-48e2-b25d-97cb9e345e56.png)
Use Powershell on AD01 via MGMT01 to create another OU called “Software Deploy”, move WKS01 and your regular named account into it, and then delete the Test OU.
```powershell
# Create another OU called Software Deploy under charlotte.local
# Move WKS01 and your regular named account into it, and then
# Delete the Test OU
# Get the domain Distinguished Name (DN)
$domainDN = (Get-ADDomain).DistinguishedName
# Create the "Software Deploy" OU
$swDeployOUDN = "OU=Software Deploy,$domainDN"
$swDeployOU = Get-ADOrganizationalUnit -Identity $swDeployOUDN
if($swDeployOU){
Write-Host "'Software Deploy' OU already exists at $swDeployOUDN"
}else{
New-ADOrganizationalUnit -Name "Software Deploy" -Path $domainDN -Description "Software Deployment OU"
Write-Host "Created $swDeployOUDN"
}
# Move WKS01 computer to new OU
$computerDN = (Get-ADComputer -Identity "WKS01-CHARLOTTE").DistinguishedName
$targetOUDN = "OU=Software Deploy,$domainDN"
Move-ADObject -Identity $computerDN -TargetPath $targetOUDN
Write-Host "Computer $computerDN added to $targetOUDN"
# Move charlotte.croce-adm to new OU
$userDN = (Get-ADUser -Identity "charlotte.croce-adm").DistinguishedName
Move-ADObject -Identity $userDN -TargetPath $targetOUDN
Write-Host "User $userDN added to $targetOUDN"
# Remove the "Protect from accidental deletion" flag from Test OU and delete
$testOU = Get-ADOrganizationalUnit -Filter {Name -eq "Test OU"}
if($testOU){
Set-ADObject -Identity $testOU -ProtectedFromAccidentalDeletion $false
Remove-ADOrganizationalUnit -Identity $testOU -Confirm:$false
Write-Host "Deleted $testOU"
}
```
## Deploying Software via GPO
- On MGMT01, download the current Putty x64-bit Windows Installer Package.
- Next, create a Share on MGMT01 named Software and place Puttys .msi in it, so users and computers (via GPO) can access & install it shortly.
- see SYS255 file share docs [here](https://git.charlotte.sh/lotte/ChamplainTechJournals/src/branch/main/sysadmin-i-sys255/lab07-lab-server-core-and-remote-administrator-tools.md#use-rsat-to-add-to-fs01-and-create-a-sales-users-share). No need to map drive to letter
- Via Group Policy Management feature on MGMT (You need to install this), create a new GPO named Deploy SW within the Software Deploy OU. \
![image](../../assets/64d738b7-1b8e-45ea-9f7d-474fc6679cfb.png)
![image](../../assets/dccadcee-10f4-4fce-ac7b-0f7b9b87f0cd.png)
- Edit the new GPO by creating a new Software installation, and assign Puttys .msi package to deploy. \
![image](../../assets/45ad5e35-665c-4861-a8be-e9aa17d6b676.png)
- With the new GPO setting, run `gpupdate /force` on WKS01, and then allow the restart when prompted. PuTTY should now be installed
> [!Note]
> An extremely common issue youll encounter in MS Window environments are the differences between Local Permissions vs. Share Permissions:
>
> Local Permissions (also called NTFS Permissions): Permissions that are applied only Locally (and not Remotely) on the OS, and affects both Local (i.e. via keyboard) and Remote (i.e. via network) account access.
>
> Share Permissions: Permissions that are applied only Remotely (and not Locally) to the OS, and affects only Remote (i.e. via network shares) account access.
>
> If both Shared & Local Permissions are set, then MOST RESTRICTIVE PERMISSION WINS. #LeastPriledgeRules -- summary [here](https://blog.netwrix.com/ntfs-vs-share-permissions)

View file

@ -0,0 +1,149 @@
# Lab07 - certs
make certain -adm account is in the Enterprise Admins
```powershell
Get-ADGroupMember "Enterprise Admins"
```
add RSAT to MGMT01. needs to run as administrator
```powershell
Install-WindowsFeature RSAT-ADCS -IncludeManagementTools
```
Start remote PowerShell session
```powershell
$session = New-PSSession -ComputerName ad01-charlotte
```
Install AD Certificate Services Role
```powershell
Invoke-Command -Session $session -ScriptBlock {
Install-WindowsFeature -Name AD-Certificate -IncludeManagementTools
# Import the ADCS module
Import-Module ADCSDeployment
}
```
Configure Enterprise Root CA
```powershell
Invoke-Command -Session $session -ScriptBlock {
Install-AdcsCertificationAuthority `
-CAType EnterpriseRootCA `
-CryptoProviderName "RSA#Microsoft Software Key Storage Provider" `
-KeyLength 4096 `
-HashAlgorithmName SHA512 `
-ValidityPeriod Years `
-ValidityPeriodUnits 7 `
-Force
}
```
Create Certificate Share
```powershell
Invoke-Command -Session $session -ScriptBlock {
# create the shared folder for certs
New-Item -Path "C:\Shares\Certs" -ItemType Directory -Force
New-SmbShare -Name "Certs" -Path "C:\Shares\Certs" -FullAccess "Domain Admins" -ChangeAccess "Authenticated Users"
# copt cert to shared directory
$cert = Get-ChildItem -Path "Cert:\LocalMachine\CA" | Where-Object {$_.Subject -like "*charlotte-ad01-CHARLOTTE-CA*"}
# export cert to shared folder
Export-Certificate -Cert $cert -FilePath "C:\Shares\Certs\charlotte-AD01-CHARLOTTE-CA.cer" -Type CERT
}
```
Install AD CS role with Certification Authority and Web Enrollment
```
Install-WindowsFeature -Name ADCS-Cert-Authority, ADCS-Web-Enrollment -IncludeManagementTools
```
Configure the Subordinate CA and generate certificate request
```powershell
Install-AdcsCertificationAuthority `
-CAType EnterpriseSubordinateCA `
-CACommonName "mgmt01-CHARLOTTE-SubCA" `
-CryptoProviderName "RSA#Microsoft Software Key Storage Provider" `
-KeyLength 4096 `
-HashAlgorithmName SHA512 `
-OutputCertRequestFile "C:\SubCARequest.req"
```
Install the Web Enrollment service
```powershell
Install-AdcsWebEnrollment
```
Move the certificate request to the Root CA, get it signed, and retrieve it
```powershell
# Copy request to Root CA's shared folder
Copy-Item -Path "C:\SubCARequest.req" -Destination "\\ad01-charlotte\Certs\"
# Sign the request on the Root CA
Invoke-Command -Session $session -ScriptBlock {
# Sign the subordinate CA certificate request
certreq -submit -config "ad01-charlotte\charlotte-AD01-CHARLOTTE-CA" -attrib "CertificateTemplate:SubCA" "C:\Shares\Certs\SubCARequest.req" "C:\Shares\Certs\SubCACert.cer"
}
# Copy the signed certificate back to the Subordinate CA
Copy-Item -Path "\\ad01-charlotte\Certs\SubCACert.cer" -Destination "C:\"
```
```powershell
# Start the CA service
Start-Service -Name CertSvc
# Install the issued certificate
certutil -installcert "C:\SubCACert.cer"
# Configure CA settings
certutil -setreg CA\CRLPeriodUnits 1
certutil -setreg CA\CRLPeriod "Weeks"
certutil -setreg CA\CRLOverlapPeriodUnits 12
certutil -setreg CA\CRLOverlapPeriod "Hours"
# Restart the service to apply changes
Restart-Service -Name CertSvc
```
```
# Verify the CA status
certutil -ping
```
Clean up the remote session
```
Remove-PSSession $session
```
___
*at this point I stopped using PS and just used the GUI*
___
### Create Certificate Template
- open the CA console: `certsrv.msc`
- Expand root cert tree > RC Certificate Templates > Manage
- Duplicate User template
- General tab: Set name "Champ Lab User"
- Subject Name: Select "Build from AD info", uncheck all email options
- Extensions: Add "Smart Card Logon" to Application Policies
- Security: set "Authenticated Users" to Read, Enroll, Autoenroll permissions
## Issue Certificate Template
- in CA console
- Right-click Certificate Templates > New > Certificate Template to Issue > Select "Champ Lab User"
## Configure Group Policy
- `gpmc.msc`
- Create GPO "Champ Lab Users" at domain level
- Edit GPO > User Configuration > Policies > Windows Settings > Security Settings > Public Key Policies
- Enable "Certificate Services Client - Auto-Enrollment"
- Check both renewal options > OK
## Test Auto-Enrollment
- on WKS01:
- `gpupdate /force`
- Verify: `gpresult /r`
- `certmgr.msc` > Personal > Certificates > Verify "Champ Lab User" certificate is present
## Windows Admin Center Installation
- Download Windows Admin Center 2019 Evaluation
- https://info.microsoft.com/ww-landing-windows-admin-center.html
- download the msi
- you will have to put in information. i just used fake info
- Express setup. Generate self-signed cert. Disable updates
- Logon via -adm account, add ad01 + wks10, install AD + DNS extensions, and uninstall Azure + Cluster extensions

View file

@ -0,0 +1,72 @@
#!/bin/bash
#
# secure-ssh.sh
# author: charlottecroce
#
# creates a new SSH user using $1 parameter
# adds a public key from the local repo or curled from the remote repo
# removes roots ability to SSH in
#
#
# Requirements:
# must run as root
# $1 = username of new user
#
# check if script is run as root
if [ $EUID -ne 0 ]; then
echo "run as root"
exit 1
fi
# check if username was provided
if [ -z $1 ]; then
echo "Usage: $0 <username>"
exit 1
fi
# vars
USERNAME=$1
AUTHORIZED_KEYS_DIR="/home/$USERNAME/.ssh"
AUTHORIZED_KEYS_FILE="$AUTHORIZED_KEYS_DIR/authorized_keys"
# create user
useradd -m -d /home/$USERNAME -s /bin/bash $USERNAME
echo "user: <$USERNAME> created"
# create .ssh directory, give perms to user
mkdir -p $AUTHORIZED_KEYS_DIR
chmod 700 $AUTHORIZED_KEYS_DIR
# try to get SSH pubkey from local repo
if [ -f "/home/charlotte/champlaintechjournals/sysadmin-ii-sys265/linux/public-keys/id_rsa.pub" ]; then
echo "key found in local repo"
cat /home/charlotte/champlaintechjournals/sysadmin-ii-sys265/linux/public-keys/id_rsa.pub >> $AUTHORIZED_KEYS_FILE
else
# if local key doesn't exist, get from github repo...
echo "no key found in local repo, cloning from github..."
git clone https://git.charlotte.sh/lotte/ChamplainTechJournals /home/$USERNAME
echo "retreived key from github repo"
cat /home/$USERNAME/champlaintechjournals/sysadmin-ii-sys265/linux/public-keys/id_rsa.pub >> $AUTHORIZED_KEYS_FILE
fi
echo "added key to $AUTHORIZED_KEYS_FILE"
# set perms, set new user as directory owner
chmod 600 $AUTHORIZED_KEYS_FILE
chown -R $USERNAME:$USERNAME $AUTHORIZED_KEYS_DIR
# disable root SSH login
sed -i 's/PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
echo "Root SSH access has been disabled"
# disable password authentication
sed -i 's/PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
echo "Password authentication has been disabled"
# Restart SSH service
echo "restarting ssh..."
systemctl restart sshd
echo "complete!"

View file

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCWgOr/kpF795P2RGym4lGHD+vXFPiTpkHIA7EjIX+/cF+XB1lZgRjjgcOMf19XjspJX4XAbrAFhX82XmIdpN0ljjspy7pPvvHjRa436LW2WYX0LB80ozZiRqTV0Ic9HOpEHKeVZCbBqoO44mMKLAlsaymuhZk1qvByxap3mjXeynd5N+tDXGltN18Nsflu3twMjfHepjbUgG4H+VzQbnItN2rIe8HWRt6MCisLCrplRWHCuOMRNMhtqhgkP5IX+XSPD4SMY2ZTCXCgRAZ1I2bwPV0YzjmXkaZur39bXh9UAr2ORhrAWR+IzgLpvjAr4hsXtYantnFu6Dp7ui/Ggs29OWYXoYaIWfD7UKdyz3/xPcg5MyYnL1KSLza5Odhj12lodrrskqwfunBIIRWjp0z6LuYxdZKj4mE7+wVWN6QQiSBkPZwfMbUf3OMSGB5krxVoOy/A6Ibg2FkgzONAHeUlW9L2inrry0jVxhuamDhGaOAjt1Rhq8asKZVRU1Er1DGtJaInN/z7gvBPIUsJbZRvJUj7EoB0RdGDcH/1U6UeSt5DXz9WRPaiEss/fv4N8snIj4hd9Jt774LR2UD8ZBQkOrFOH72noLx6GDrBeIZ//Hl8rO8ja+JyeVoNLqjKzwrLhbmPsdn2/zXB0asDq2vI0yk+YUlAldG38/lhZ/9EwQ== sys265

View file

@ -0,0 +1,38 @@
# SYS265 - Network Configuration
## pfsense router/gateway/firewall
upstream gateway: 10.0.17.2 \
my unique WAN IP: 10.0.17.104 \
net adapter 1: WAN \
net adapter 2: LAN
### wks01-charlotte - Windows workstation
IP address: 10.0.5.100/24 \
Default Gateway: 10.0.5.2\
DNS: 10.0.5.5
### ad01-charlotte - Windows server core
IP Address: 10.0.5.5/24 \
Gateway: 10.0.5.2\
DNS: 10.0.5.2
### mgmt01-charlotte - Windows server
IP address: 10.0.5.10/24 \
Gateway: 10.0.5.2\
DNS: 10.0.5.5
### nmon1-charlotte -
IP address: 10.0.5.11/24 \
Gateway: 10.0.5.2 \
DNS: 10.0.5.5
### web01-charlotte - web server
IP address: 10.0.5.20/24
Gateway: 10.0.5.2 \
DNS: 10.0.5.5 \
### docker01-charlotte -
IP address: 10.0.5.12/24
Gateway: 10.0.5.2 \
DNS: 10.0.5.5 \

View file

@ -0,0 +1,97 @@
# SYS265 - DHCP Lab
# 1/31/25
# Get Username
function get_username(){
Write-Host 'Username:'$env:USERNAME
}
# Get IP Address
function get_ip(){
$ip_address = (Get-NetIPAddress -AddressFamily IPv4 | Select IPv4Address | Where-Object { $_.IPv4Address -ne "127.0.0.1" } | Format-Table -HideTableHeaders | Out-String).Trim()
Write-Host 'IP Address:'$ip_address
}
# Get DHCP Server Address
function get_dhcp(){
$dhcp_address = (Get-CimInstance Win32_NetworkAdapterConfiguration | Select DHCPServer | Format-Table -HideTableHeaders | Out-String).Trim()
Write-Host 'DHCP Server:'$dhcp_address
$dhcp_lease = (Get-CimInstance Win32_NetworkAdapterConfiguration | Select DHCPLeaseExpires | Format-Table -HideTableHeaders | Out-String).Trim()
Write-Host 'Lease Expiration:'$dhcp_lease
}
# Get Gateway IP
function get_gateway(){
$gateway_address = (Get-CimInstance Win32_NetworkAdapterConfiguration | Select DefaultIPGateway | Format-Table -HideTableHeaders | Out-String).Trim()
Write-Host 'Default Gateway:'$gateway_address
}
# Get DNS Server IP
function get_dns(){
$dns_address = ((Get-DnsClientServerAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -ne "loopback" }).ServerAddresses | Out-String).Trim()
Write-Host 'DNS Server:'$dns_address
}
clear
$Prompt = "`nChoose number for operation`n"
$Prompt += "1. All`n"
$Prompt += "2. Username`n"
$Prompt += "3. IP`n"
$Prompt += "4. DHCP`n"
$Prompt += "5. Default Gateway`n"
$Prompt += "6. DNS`n"
$Prompt += "7. exit"
$operation = $true
while($operation){
Write-Host $Prompt | Out-String
$choice = Read-Host
Write-Host "----------"
if($choice -eq 1){
get_username
get_ip
get_dhcp
get_gateway
get_dns
}
elseif($choice -eq 2){
get_username
}
elseif($choice -eq 3){
get_ip
}
elseif($choice -eq 4){
get_dhcp
}
elseif($choice -eq 5){
get_gateway
}
elseif($choice -eq 6){
get_dns
}
elseif($choice -eq 7){
Write-Host "Goodbye" | Out-String
exit
$operation = $false
}
else{
Write-Host "Invalid Input" | Out-String
}
Write-Host "----------"
}