Archive for the ‘ansible’ Category

Upgrade awx-cli:

pip install ansible-tower-cli --upgrade

awx-cli config verify_ssl False

Backup AWX

Make sure AWX containers are running and you can login to Web GUI

docker ps

Export Credentials, Inventories, Job templates and Workflows

awx-cli receive -u admin -p 'password' -h http://awx-old --credential all > credential.json
awx-cli receive -u admin -p 'password' -h http://awx-old --project all > project.json
awx-cli receive -u admin -p 'password' -h http://awx-old --inventory all > inventory.json
awx-cli receive -u admin -p 'password' -h http://awx-old --job_template all > job_template.json
awx-cli receive -u admin -p 'password' -h http://awx-old --workflow all > workflow.json

Installing new AWX (on new machine)

Install epel-relase, AWX prerequisites,Docker, docker-compose and Ansible

yum install -y epel-release 
yum -y install git gcc gcc-c++ nodejs gettext device-mapper-persistent-data lvm2 bzip2 python-pip
yum-config-manager --addrepo=https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce
# Enable and start Docker service
systemctl enable --now docker.service
# install docker-compose
pip install docker-compose
# install Ansible
yum install ansible
# Start and enable Ansible
systemctl enable ansible && systemctl start ansible

Installing Ansible AWX 

git clone --depth 50 https://github.com/ansible/awx.git
#  set a custom admin_password for AWX and PostgreSQL in inventory file.
cd awx/installer
sed -i 's|admin_password=.*|admin_password=pass|g' inventory
# Add secret_key in inventory file.
openssl rand -base64 30
lE7TAtB/EGDfZp2vYJWY1jVwn3nDh3H+a0pqhXHZ
sed -i 's|secret_key=.*|secret_key=lE7TAtB/EGDfZp2vYJWY1jVwn3nDh3H+a0pqhXHZ|g' inventory

Customize other directives if needed in inventory file, for example host_port=9000 and postgres folder – postgres_data_dir = "/data"

Install AWX Ansible

ansible-playbook -i inventory install.yml

# Check if all 5 containers are installed
docker ps

Allow HTTP/HTTPS service in Linux firewall

firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

In this example, AWX will be available on port 9000

Try Logging in: http://awx-new:9000

Redirecting HTTP traffic to HTTPS

We’ll use nginx as reverse proxy to redirect HTTP traffic on port 9000 to HTTPS.

yum install nginx
systemctl enable nginx

Create self-signed certificate:

cd /etc/awx
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/awx/awx.key -out /etc/awx/awx.crt

Generating a 2048 bit RSA private key
.....................................+++
.........................................................+++
writing new private key to '/etc/awx/awx.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:SR
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:Zemoon
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:awx-new.test.com
Email Address []:

Edit /etc/nging/nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  awx-new.test.com;
        add_header Strict-Transport-Security max-age=2592000;
        rewrite ^ https://$server_name$request_uri? permanent;
        root         /example;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }


server
{
 listen 443 ssl http2;
 server_name awx-new.test.com;

location /
 {
   proxy_http_version 1.1;
   proxy_set_header Host $host;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header X-Forwarded-Proto $scheme;
   proxy_set_header Upgrade $http_upgrade;
   proxy_set_header Connection "upgrade";
   proxy_pass http://192.168.1.2:9000/;
 }

ssl on;
ssl_certificate /etc/awx/awx.crt;
ssl_certificate_key /etc/awx/awx.key;
ssl_session_timeout 5m;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5:HIGH:!aNULL;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

access_log /var/log/nginx/awx.access.log;
error_log /var/log/nginx/awx.error.log;
}

Start nginx (systemctl start nginx) and try accessing AWX https://awx-new.test.com

Restoring AWX

Install awx-cli

pip install ansible-tower-cli --upgrade

awx-cli config verify_ssl False

Manually create organization: Organizations-“plus” sign

Create Teams (if you had any on old AWX)

# Restore Credentials 

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 credential.json

#P lease note that passwords won't be exported, you'll need to enter it # manually after usernames are imported (Credentials section in Web GUI)

 # restore project

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 project.json

# restore inventories

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 inventory.json

# before restoring job templates, remove line which contains string credential

sed -i '/\bcredential\b/d' job_template.json

# restore job templates

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 job_template.json

# restore workflows

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 workflow.json

Active Directory Authentication

LDAP config won’t be exported so we need to set it up manually: In Web portal click Settings-Authentication-LDAP

LDAP SERVER: default

LDAP SERVER URI: ldap://1.2.3.4:389

LDAP BIND DN: CN=Ansible,OU=ServiceUsers,OU=test,DC=com

LDAP BIND PASSWORD: password

LDAP GROUP TYPE: ActiveDirectoryGroupType

LDAP USER SEARCH: [
 "OU=Users,OU=test,DC=com",
 "SCOPE_SUBTREE",
 "(sAMAccountName=%(user)s)"
]
 
LDAP GROUP SEARCH: [
 "CN=Users,DC=test,DC=com",
 "SCOPE_SUBTREE",
 "(objectClass=group)"
]

LDAP ORGANIZATION MAP: {
 "My Organization": {
  "remove_admins": false,
  "admins": "CN=Ansible, OU=Security,OU=Groups,OU=test,DC=com"
 }
}

 LDAP over SSL (LDAPS)

Install the certificates on your machine where you’re running docker on. During the installation provide the path to root certs (inventory file in installer dir):

ca_trust_dir=/etc/pki/ca-trust/source/anchors

If you have AWX already installed and don’t want to re-deploy – install certificates to awx_web and awx_task containers.

Copy cert and go to the container, e.g.

docker cp cert.crt awx_task:/etc/pki/ca-trust/source/anchors/your_org.crt
docker exec -it awx_task /bin/bash

Finally install the cert:

update-ca-trust enable
update-ca-trust extract

Repeat for the second container (awx_web).

Login to AWX GUI-Setting-Authentication-LDAP

in LDAP SERVER URI set:

ldaps://test.com:636

It’s presumed Chocolatey server will be installed on D drive,it’s presumed Chocolatey server has no internet access.

Choco installation files are obtained in following way:

On any windows machine with internet access following has been done:

  • installed chocolatey
  • after chocolatey has been installed following command has been executed:
    choco install chocolatey.server
  • all required files are downloaded to C:\tools folder

Capture.PNG

Copy tools folder somewhere to Ansible server, Ansible playbook will copy  it to D drive on Windows server.

Folder structure:

|—————–winplaybook/choco.yml   chocoserver/tools/

|—————group_vars/

|             | ————–features/features.yml

|————–windows/vars_win.yml   vaul_win.yml

features.yml contains list of IIS features and IIS users

---
features:
- Web-Server
- Web-Asp-Net45
- Web-AppInit 

users:

- IIS_IUSRS
- IUSR
- IIS APPPOOL\ChocolateyServer

chocoserver/tools contains chocolatey server installation (copied from windows machine with internet access)

Chocolatey API key is in vars_win.yml (unencrypted-point to vault_win.yml) and vault_win.yml (encrypted)

vars_win.yml:

api_key: '{{ vault_api_key }}'

vault_win.yml:

vault_api_key: myapi

Playbook will copy Chocolatey server files to D drive, installs IIS server and features,removes default IIS web site, creates Chocolatey application pool, sets ACL permissions on D:\tools\chocolatey.server and D:\tools\chocolatey.server\App_Data,creates Chocolatey IIS site and changes default API key

– name: install choco server
hosts: dc2
vars_files:
– group_vars/windows/vars_win.yml
– group_vars/features/features.yml
gather_facts: yes
tasks:
– name: Copy Chocolatey server to D drive
win_copy:
src: /root/win_playbooks/choco_server/
dest: D:\
– name: Ensure IIS is installed
win_feature:
name: Web-Server
state: present
include_management_tools: True
– name: Ensure IIS Web-Server and ASP.NET are installed
win_feature:
name: ‘{{ item }}’
state: present
with_items: ‘{{ features }}’
– name: Ensure Default Web Site is not present
win_iis_website:
name: “Default Web Site”
state: absent
#- name: Chocolatey.server package is installed
# win_chocolatey:
# name: “chocolatey.server”
# state: present
– name: Configure AppPool for Chocolatey.server
win_iis_webapppool:
name: ChocolateyServer
state: started
attributes:
enable32BitAppOnWin64: true
managedRuntimeVersion: v4.0
managedPipelineMode: Integrated
startMode: AlwaysRunning
autoStart: true
– name: Grant read permissions to D:\tools\chocolatey.server
win_acl:
user: ‘{{ item }}’
path: D:\tools\chocolatey.server
rights: Read
state: present
type: allow
inherit: ContainerInherit, ObjectInherit
progagation: InheritOnly
with_items: ‘{{ users }}’
– name: Grant IIS APPPOOL\ modify permissions to D:\tools\chocolatey.server\App_Data
win_acl:
user: ‘{{ item }}’
path: D:\tools\chocolatey.server
rights: Modify
state: present
type: allow
inherit: ContainerInherit, ObjectInherit
progagation: InheritOnly
with_items: ‘{{ users }}’
– name: Create Chocolatey IIS site
win_iis_website:
name: “chocolatey”
state: started
port: 80
#ip: 127.0.0.1
application_pool: “ChocolateyServer”
physical_path: D:\tools\chocolatey.server
parameters: logfile.directory:c:\ChocolateyServer\logs
register: website
– name: Change default API key
win_lineinfile:
path: D:\tools\chocolatey.server\web.config
regexp: ‘<add key=”apiKey” value=”chocolateyrocks” />’
line:’         <add key=”apiKey” value=”{{ api_key }}”/>’
state: present

Unlike other tasks, this one requires runas (become) permissions. So, we need to specify become statement in playbook, and to add following directives in group_vars folder (see this guide how to create it.

add 4 “ansible_become” lines as per example

---
ansible_user: Administrator
ansible_password: Pass
ansible_connection: winrm
ansible_port: 5986
ansible_winrm_server_cert_validation: ignore
ansible_become: yes
ansible_become_user: Administrator
ansible_become_pass: Passw
ansible_become_method: runas
Both are same account,it’s local admin account promoted to Domain Administrator after creating AD Domain, the reason why we need to add those 4 lines is because renaming AD joined machines required Active Directory credentials, those 4 “ansible_become” lines instruct Ansible to use domain administrator credentials instead of local administrator.
- name: Change computer name
  hosts: dc2
  tasks:
   - name: Change host name
     become: yes
     win_hostname:
       name: server2
     register: name_changed
   - name: reboot server after hostname changes
     win_reboot:
       msg: "Computer name changed,rebooting...."
       pre_reboot_delay: 15
     when: name_changed.changed

 

In this example Page file will be moved to D drive, in order for Ansible to “track changes” file C:\Pagefile.log will be created after Page file is moved and server will be restarted afterwards.

In this example page file is set to automatic (InitialSize = 0; MaximumSize = 0), we can set custom Initial/Maximum size (in MB).

- name: Moving page file to another drive
  hosts: winserver
  gather_facts: yes
  tasks:
   - name: "Move Page File to D Drive"
     win_shell: |
       $a=Get-WmiObject -Query "select * from Win32_PageFileSetting"
       if ($a.Name -like 'C:\pagefile.sys') {
       $CurrentPageFile = Get-WmiObject -Query "select * from Win32_PageFileSetting where name='c:\\pagefile.sys'"
       $CurrentPageFile.delete()
       Set-WMIInstance -Class Win32_PageFileSetting -Arguments @{name="d:\pagefile.sys";InitialSize = 0; MaximumSize = 0}
       } write-output "Done" | out-file C:\Pagefile.log -Append
     args:
      creates: C:\Pagefile.log
     register: page
   - name: reboot server
     win_reboot:
       msg: "Page file moved,rebooting..."
       pre_reboot_delay: 15
     when: page.changed

Ansible have no module for setting Domain Group Policies,but we can use PowerShell commands. If we need to create Custom GPO and link it to some GPO, we can do it also by Powers shell – by setting Registry Values.

The key must be in one of the two following registry hives:

  • HKEY_LOCAL_MACHINE (HKLM) for a registry-based policy setting in Computer Configuration.
  • HKEY_CURRENT_USER (HKCU) for a registry-based policy setting in User Configuration.

Bellow is example for setting Screen Saver TimeOut to 900 seconds for User Configuration Settings GPO.

Capture

New GPO named BO-1-Desktops is created and linked to test OU.

- name: Configure GPO
        hosts: winserver
        tasks: 
          - name: Set ScreenSaver Timeout
            win_shell: | 
              New-GPLink -Name "BO-1-Desktops" -Target 
 "OU=test,DC=ad,DC=contoso,DC=com";
              Set-GPRegistryValue -Name "BO-1-Desktops" -KEY "HKCU\Software\Policies\Microsoft\Windows\Control Panel\Desktop" -ValueName "ScreenSaveTimeOut" -Type DWORD      -Value 900 > C:\screensaverGPO.txt
            args: 
              creates: C:\screensaverGPO.txt

Script won’t be executed if C:\screensaverGPO.txt exists.

Example for creating DNS zone

- name: Create DNS
  hosts: winserver
  tasks:
   - name: Create Forward lookup zone
     win_shell: |
       try {$getdns=Get-DnsServerZone -Name "west01.contoso.com" -ErrorAction SilentlyContinue
       if ($getdns -eq $null) {Add-DnsServerPrimaryZone -Name "west01.contoso.com"       -ReplicationScope "Forest" -PassThru > c:\dnszone.log}
       } catch {write-host "ok"}
     args:
       creates: C:\dnszone.log

This post explained how to use it with Puppet, in this post we’ll do the same.

Powershell script is doing following:

  •  reads JSON file above
  • Creates subnets defined from JSON file
  • Creates sites defined in JSON file
  • Assigns subnet to AD site (as specified in JSON file)

JSON and PS1 files are located in  /root/win_playbooks/files/ folder.

Both files will be copied to C:\Script

Script will be running only if file C:\Script\Logs\ADSite.log is present.

- name: Configure AD sites
hosts: winserver
gather_facts: yes
tasks:
- name: Create folder
    win_file:
     path: C:\Script
     state: directory
- name: Copy files
  win_copy:
     src: /root/win_playbooks/files/
     dest: C:\Script\
- name: Run Script
  win_shell: C:\Script\createsite.ps1
  args:
     creates: C:\Script\logs\CreateADSIte.log

 

File structure is same as in this post.

Playbook for Joining Machine to AD Domain:

name: install second domain controller
 hosts: dc2
 vars_files:
 - group_vars/windows/vault_win.yml
 gather_facts: yes
 tasks:
 - name: Configure Primary DNS Server
 win_dns_client:
     adapter_names: 'Ethernet 2'
     ipv4_addresses:
       - 192.168.1.182
 - name: Join to the domain
   win_domain_membership:
     dns_domain_name: '{{ dns_name }}'
     domain_admin_user: '{{ domain_admin_user }}'
     domain_admin_password: '{{ vault_ad_admin_pass }}'
     state: domain
 register: domain_state
 - name: Reboot after joining
   win_reboot:
     msg: "Joining Domain.Rebooting..."
     pre_reboot_delay: 15
   when: domain_state.reboot_required</pre>