Repository: apache/airavata-custos (language: python)

Issue:
Upgrade Dependencies
Upgrade to upgrade to Apache Tomcat 9.0.68 
Upgrade to org.springframework:spring- beans@5.2.22.RELEASE or later
Upgrade to org.springframework.security:spring-security- crypto@5.5.7 or later
Upgrade to org.springframework:spring- core@5.2.22.RELEASE or later
 Upgrade to Keycloak 20.0.0 or later None 
Upgrade to org.dom4j:dom4j@2.1.3
Upgrade to io.netty:netty-transport@4.1.84
Upgrade to io.netty:netty-codec-http@4.1.84.Final
merge staging branch

Writing ansible scripts to deploy Custos
As part of the Custos baremetal deployment effort - we need to write ansible scripts to configure and automate deployments.
Upgrade Dependencies
Upgrade to upgrade to Apache Tomcat 9.0.68 
Upgrade to org.springframework:spring- beans@5.2.22.RELEASE or later
Upgrade to org.springframework.security:spring-security- crypto@5.5.7 or later
Upgrade to org.springframework:spring- core@5.2.22.RELEASE or later
 Upgrade to Keycloak 20.0.0 or later None 
Upgrade to org.dom4j:dom4j@2.1.3
Upgrade to io.netty:netty-transport@4.1.84
Upgrade to io.netty:netty-codec-http@4.1.84.Final


Discussion / hints:

Fix patch:
diff --git a/ansible/.gitignore b/ansible/.gitignore
new file mode 100644
index 000000000..2a22f0cd5
--- /dev/null
+++ b/ansible/.gitignore
@@ -0,0 +1,2 @@
+ENV
+vault_pass
diff --git a/ansible/README.md b/ansible/README.md
new file mode 100644
index 000000000..cbf4d2fbd
--- /dev/null
+++ b/ansible/README.md
@@ -0,0 +1,193 @@
+# Apache Custos Ansible
+
+Ansible scripts to configure and install Apache Custos pre-requisites and deploy the application on bare-metal web servers. The deployment process is divided into 4 steps - 
+1. [Prerequisites](#prerequisites)
+2. [Initial VM set up](#set-up-vms)
+3. [Generate SSL certificates](#generate-ssl-certificates)
+4. [Deploy application](#deploy-application)
+5. [Deploy application with data migration](#data-migration)
+
+## Prerequisites<a name="prerequisites"/>
+Make sure you have installed all of the following prerequisites on your development machine:
+* Git - [Download & Install Git](https://git-scm.com/downloads). OSX and Linux machines typically have this already installed.
+* Python3 - [Download and Install Python3](https://www.python.org/downloads/). You can also use your system's package manager to install the latest stable version of python3.
+
+Note: the following assumes a Bash shell.
+
+Verify if git was installed successfully.
+```bash
+git --version
+```
+Verify if python3 was installed successfully.
+```bash
+python3 --version
+```
+Clone Custos git repo and switch branch.
+```bash
+git clone https://github.com/apache/airavata-custos.git
+cd airavata-custos
+git switch baremetal
+```
+Create a virtual environment in the ansible directory
+```bash
+cd ansible
+python3 -m venv ENV
+```
+Activate the virtual environment. (You'll need to do this each time before using ansible commands)
+```bash
+source ENV/bin/activate
+```
+The requirements.txt file contains ansible and any other dependencies. Install it by running the following command:
+```bash
+pip install -r requirements.txt
+```
+## Set up VMs<a name="set-up-vms"/>
+You will need 3 Linux VMs (Preferably Ubuntu 20.04) for Custos Deployment. Make sure you have registered domain names for each of them.
+* _VM #1_: for hosting **Keycloak**
+* _VM #2_: for hosting **Hashicorp Vault** and **Consul**
+* _VM #3_: for hosting **Custos Spring Boot application**.
+
+### Configure Ansible vars with VM details
+Now, you need to configure Ansible vars with the domain names of these VMs so that ansible knows where to install custos dependencies.
+
+Open the file `test/hosts.yml`. Set `ansible_host` for `custos`, `keycloak` and `hashicorp` with their respective domain names. For ex:
+
+```yml
+all:
+  hosts:
+    custos:
+      ansible_host: my-custos-domain.com
+      ⋮
+    keycloak:
+      ansible_host: my-keycloak-domain.com
+      ⋮
+    hashicorp:
+      ansible_host: my-hashicorp-domain.com
+      ⋮
+```
+Ansible connects to these VMs using `ssh`. To allow ansible to do this, you will also need to provide it with ssh passwords for these VMs. To maintain security, these passwords cannot be exposed in plaintext. We use ansible's `ansible-vault` command to encrypt these password strings.
+
+Open the file `test/group_vars/all/vault.yml`. You will need to decrypt the file to access it (it's been encrypted using ansible-vault for security).
+Make sure you put the password text in this file - `ansible/vault_pass`. You can reach out to the dev team to get the password for test env.
+Here's the command:
+```bash
+ansible-vault decrypt inventories/test/group_vars/all/vault.yml
+```
+
+In the file `test/group_vars/all/vault.yml`, look for `keycloak_ssh_password`, `hashicorp_ssh_password` and `custos_ssh_password` variables. Set these variables with their respective password strings. For ex:
+```yml
+⋮
+keycloak_ssh_password: XXX..XXX
+hashicorp_ssh_password: YYY...YYY
+custos_ssh_password: ZZZ...ZZZ
+⋮
+```
+
+Anytime you change the `vault.yml` file, don't forget to encrypt it back again.
+Here's the command to encrypt:
+```bash
+ansible-vault encrypt inventories/test/group_vars/all/vault.yml
+```
+
+Now that you've configured the ssh user and password details for your VMs, we can install nginx on each of these servers at once by running the following command:
+```bash
+ansible-playbook -i inventories/test/ custos.yml --tags env_setup
+```
+
+## Generate SSL certificates<a name="generate-ssl-certificates"/>
+The `env_setup.yml` playbook installed `certbot` along with `nginx` in your VMs. 
+
+Now **Certbot** will help us manage letsencrypt SSL certificates. You need to generate SSL certs for each of your 3 VMs.
+
+### Generate letsencrypt certificates
+SSH into your VMs with your user:
+```bash
+ssh <myuser>@<my-domain.com>
+```
+Run the following command:
+```bash
+sudo certbot --nginx -d <my-domain.com> -m <myemail@gmail.com> --agree-tos --no-eff-email --redirect
+```
+Certbot generates a cert file (`fullchain.pem`) and a keyfile (`privkey.pem`) in the following location in your VM - `/etc/letsencrypt/live/<my-domain.com>/`
+
+### Generate pkcs12 certs from pem files
+Run the following commands to generate pkcs12 truststore files from you cert and key files. You will be asked to create a password for the pkcs12 file, keep the password in a safe location.
+
+In the hashicorp VM:
+```bash
+sudo openssl pkcs12 -export -out certs/vault-client-truststore.pkcs12 -inkey /etc/letsencrypt/live/<my-hashicorp-domain.com>/privkey.pem -in /etc/letsencrypt/live/<my-hashicorp-domain.com>/fullchain.pem
+```
+In the keycloak VM:
+```bash
+sudo openssl pkcs12 -export -out certs/keycloak-client-truststore.pkcs12 -inkey /etc/letsencrypt/live/<my-keycloak-domain.com>/privkey.pem -in /etc/letsencrypt/live/<my-keycloak-domain.com>/fullchain.pem
+```
+You should see the respective pkcs12 file in the `~/certs` folder.
+
+Now, you need to add the pkcs12 passwords in the ansible vars.
+
+In the file `test/group_vars/all/vault.yml`. Look for `hashicorp_pkcs12_passphrase` and `keycloak_pkcs12_passphrase` variables. Set these variables with their respective password strings. For ex:
+```yml
+⋮
+# pkcs12 passwords
+hashicorp_pkcs12_passphrase: XXX...XXX
+keycloak_pkcs12_passphrase: YYY...YYY
+⋮
+```
+
+## Deploy application<a name="deploy-application"/>
+You're just one step away from deploying Custos. The following command runs the ansible playbook `custos.yml` which has roles to install all dependencies and deploy Custos on the given VM.
+```bash
+ansible-playbook -i inventories/test/ custos.yml
+```
+Check if custos core and integration services are up and running using the following commands:
+```bash
+systemctl status intcustos
+```
+```bash
+systemctl status corecustos
+```
+
+## Deploy application with data migration<a name="data-migration"/>
+When deploying Custos, you may want to import data from your old servers to the new ones. We can make use of ansible to automate this data migration.
+
+You need to configure ansible vars with the domain names of the old VMS.
+
+Open the file `test/hosts.yml`. Set ansible_host and ansible_user for `old_custos`, `old_keycloak` and `old_hashicorp` with their respective domain names and ssh users. For ex:
+```yml
+    ⋮
+    old_custos:
+      ansible_host: oldcustos.org
+      ansible_user: test_user
+    old_keycloak:
+      ansible_host: oldkeycloak.org
+      ansible_user: test_user
+    old_hashicorp:
+      ansible_host: oldvault.org
+      ansible_user: test_user
+    ⋮
+```
+Make sure that passwordless ssh authentication is set up from your master node to the old servers.
+
+Now Generate backups in your old servers. By default, ansible will load the backups from the locations specified in the file: `ansible/roles/migrate_db/tasks/main.yml`
+Verify that these backups exist before running the ansible-playbook command.
+
+
+To deploy Custos with data migration, run the following command:
+```bash
+ansible-playbook -i inventories/test/ custos.yml --tags migrate_db,all
+```
+If you don't see the backups loaded successfully - verify that the backups were transferred from the source locations to the master node (in folder tmp)
+## Useful commands
+- Deploy Custos with verbose option for debug messages:
+```bash
+ansible-playbook -i inventories/{inventory}/ custos.yml -vvv
+```
+Adding multiple -v will increase the verbosity, the builtin plugins currently evaluate up to -vvvvvv. A reasonable level to start is -vvv, connection debugging might require -vvvv.
+- Decrypt ansible-vault strings
+```bash
+ansible all -i inventories/test/ -e '@inventories/test/group_vars/all/vars.yml' -m debug -a 'var=secret_string'
+```
+- Encrypt a string using `ansible-vault`
+```bash
+ansible-vault encrypt_string "MySecureString"
+```
diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg
new file mode 100644
index 000000000..82f67dcc7
--- /dev/null
+++ b/ansible/ansible.cfg
@@ -0,0 +1,3 @@
+[defaults]
+host_key_checking = false
+vault_password_file = vault_pass
diff --git a/ansible/custos.yml b/ansible/custos.yml
new file mode 100644
index 000000000..913aec3fb
--- /dev/null
+++ b/ansible/custos.yml
@@ -0,0 +1,55 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- hosts: old_custos
+  roles:
+    - role: migrate_db # execute migrate_db role only when migrate_db tag is specified
+      tags: [migrate_db, never]
+- hosts: old_keycloak
+  roles:
+    - role: migrate_db
+      tags: [migrate_db, never]
+- hosts: old_hashicorp
+  roles:
+    - role: migrate_db
+      tags: [migrate_db, never]
+- hosts: hashicorp
+  roles:
+    - role: env_setup # execute env_setup role only when env_setup tag is specified
+      tags: [env_setup, never]
+    - nginx
+    - consul
+    - vault
+- hosts: keycloak
+  roles:
+    - role: env_setup
+      tags: [env_setup, never]
+    - nginx
+    - keycloak
+- hosts: custos
+  roles:
+    - role: env_setup
+      tags: [env_setup, never]
+    - nginx
+    - database
+    - zookeeper
+    - kafka
+    - custos
\ No newline at end of file
diff --git a/ansible/requirements.txt b/ansible/requirements.txt
new file mode 100644
index 000000000..a1fb8c0c5
--- /dev/null
+++ b/ansible/requirements.txt
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+ansible~=3.4.0
diff --git a/ansible/roles/consul/handlers/main.yml b/ansible/roles/consul/handlers/main.yml
new file mode 100644
index 000000000..f8412d50d
--- /dev/null
+++ b/ansible/roles/consul/handlers/main.yml
@@ -0,0 +1,25 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+# handlers file for consul-server
+- name: restart consul
+  service: name=consul state=restarted enabled=yes
+  become: yes
diff --git a/ansible/roles/consul/tasks/main.yml b/ansible/roles/consul/tasks/main.yml
new file mode 100644
index 000000000..d02f4bb64
--- /dev/null
+++ b/ansible/roles/consul/tasks/main.yml
@@ -0,0 +1,81 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: get consul zip
+  get_url:
+    dest: "/etc/{{ consul_zip_file }}"
+    url: "https://releases.hashicorp.com/consul/{{ consul_version }}/{{ consul_zip_file }}"
+  become: yes
+
+- name: ensure unzip present
+  apt:
+    name: unzip
+    update_cache: yes
+  become: yes
+
+- name: place unzipped consul on path
+  unarchive:
+    src: "/etc/{{ consul_zip_file }}"
+    dest: "{{ consul_install_dir }}"
+    remote_src: yes
+  become: yes
+
+- name: ensure directories for data and config exists
+  file:
+    path: "{{ item }}"
+    state: directory
+  with_items:
+    - "{{ consul_config_dir }}"
+    - "{{ consul_data_dir }}"
+  become: yes
+
+- name: send consul configuration file
+  template:
+    dest: "{{ consul_config_dir }}/config.json"
+    src: consul.config.j2
+  become: yes
+
+- name: ensure consul service file exists
+  template:
+    dest: /etc/systemd/system/consul.service
+    src: consul.service.j2
+    force: yes
+    mode: 0644
+  become: yes
+
+- name: restart consul
+  service:
+    name: consul
+    state: restarted
+  become: yes
+
+- name: Copy snapshot from master node to new server
+  copy:
+    src: tmp/primary.snap
+    dest: /home/exouser/backups/
+  ignore_errors: yes
+
+#- name: import snapshot to consul server
+
+- name: Reload systemd daemons
+  command: systemctl daemon-reload
+  notify: restart consul
+  become: yes
diff --git a/ansible/roles/consul/templates/consul.config.j2 b/ansible/roles/consul/templates/consul.config.j2
new file mode 100644
index 000000000..aba819526
--- /dev/null
+++ b/ansible/roles/consul/templates/consul.config.j2
@@ -0,0 +1,14 @@
+{
+    "node_name": "example",
+    "addresses": {
+        "http": "{{ ansible_facts['all_ipv4_addresses'] | last }} 127.0.0.1"
+    },
+    "server": true,
+    "advertise_addr": "{{ ansible_facts['all_ipv4_addresses'] | last }}",
+    "client_addr": "127.0.0.1 {{ ansible_facts['all_ipv4_addresses'] | last }}",
+    "connect": {
+        "enabled": true
+    },
+    "data_dir": "{{ consul_data_dir }}",
+    "bootstrap": true
+}
\ No newline at end of file
diff --git a/ansible/roles/consul/templates/consul.service.j2 b/ansible/roles/consul/templates/consul.service.j2
new file mode 100644
index 000000000..b0a4e399b
--- /dev/null
+++ b/ansible/roles/consul/templates/consul.service.j2
@@ -0,0 +1,10 @@
+[Unit]
+Description=solo consul server example
+
+[Service]
+WorkingDirectory={{ consul_config_dir }}
+User=root
+ExecStart={{ consul_install_dir }}/consul agent -config-dir={{ consul_config_dir }}
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/ansible/roles/custos/files/start_envoy_proxy.sh b/ansible/roles/custos/files/start_envoy_proxy.sh
new file mode 100644
index 000000000..6cb6240b3
--- /dev/null
+++ b/ansible/roles/custos/files/start_envoy_proxy.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+if ! docker ps --format "apachecustos/custos-rest-proxy:latest" | grep -w apachecustos/custos-rest-proxy &> /dev/null; then
+  docker run -it -d --restart always  -v $(pwd)/logs:/var/log/envoy -e ENVOY_UID=777  -p 10000:50000    apachecustos/custos-rest-proxy:latest   -c /etc/envoy/envoy.yaml
+fi
\ No newline at end of file
diff --git a/ansible/roles/custos/handlers/main.yml b/ansible/roles/custos/handlers/main.yml
new file mode 100644
index 000000000..f85fc12cb
--- /dev/null
+++ b/ansible/roles/custos/handlers/main.yml
@@ -0,0 +1,21 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
\ No newline at end of file
diff --git a/ansible/roles/custos/tasks/main.yml b/ansible/roles/custos/tasks/main.yml
new file mode 100644
index 000000000..12c095ff9
--- /dev/null
+++ b/ansible/roles/custos/tasks/main.yml
@@ -0,0 +1,117 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: Install Custos pre-requisites (Debian)
+  apt: name={{ item }} state=latest update_cache=yes
+  with_items:
+    - maven
+  become: yes
+  when: ansible_os_family == "Debian"
+
+- name: Create Custos deployment directory {{ custos_deployment_dir }}
+  become: yes
+  file: path={{ custos_deployment_dir }}
+    state=directory
+    mode=0755
+    owner={{ user }}
+    group={{ group }}
+
+- name: Create Custos source directory
+  become: yes
+  file: path={{ custos_source_dir }}
+    state=directory
+    mode=0755
+    owner={{ user }}
+    group={{ group }}
+
+- name: git checkout from Custos github repo {{ custos_repo }} branch {{ custos_git_branch }}
+  git: repo="{{ custos_repo }}"
+    dest="{{ custos_source_dir }}"
+    version="{{ custos_git_branch }}"
+  register: checkout
+  tags: update
+  become: yes
+  become_user: "{{ user }}"
+
+- name: Run Custos maven build
+  command: mvn clean install -Dmaven.test.skip=true chdir="{{ custos_source_dir }}/"
+  environment:
+    MAVEN_OPTS: "-Xmx2048m"
+  register: build
+  tags: update
+  become: yes
+  become_user: "{{ user }}"
+
+- name: Delete lib directories of the distributions
+  file:
+    state: absent
+    path: "{{ custos_deployment_dir }}/{{ item }}"
+  with_items:
+    - "Custos-Core-Services-Server-{{custos_distribution_version}}/lib"
+    - "Custos-Integration-Services-Server-{{custos_distribution_version}}/lib"
+  become: yes
+  become_user: "{{ user }}"
+  ignore_errors: yes
+
+- name: Copy Custos distributions to Custos deployment directory
+  unarchive: "src={{ custos_source_dir }}/{{ item }}
+              dest={{ custos_deployment_dir }}/ copy=no"
+  with_items:
+    - "custos-core-services-server/target/Custos-Core-Services-Server-{{custos_distribution_version}}-bin.zip"
+    - "custos-integration-services-server/target/Custos-Integration-Services-Server-{{custos_distribution_version}}-bin.zip"
+  become: yes
+  become_user: "{{ user }}"
+
+- name: Copy hashicorp and keycloak truststore files
+  copy:
+    src: "{{ custos_source_dir }}/custos-core-services-server/src/main/dist/conf/{{ item }}"
+    dest: /home/ubuntu/{{ item }}
+    remote_src: yes
+  with_items:
+    - keycloak-client-truststore.pkcs12
+    - vault-client-truststore.pkcs12
+  become: yes
+
+- name: Copy Custos property files
+  template: "src={{ item.name }}
+            dest={{ custos_deployment_dir }}/{{ item.dir }}/conf/{{ item.target }}
+            owner={{ user }}
+            group={{ group }}
+            mode=\"u=rw,g=r,o=r\""
+  with_items:
+    - { name: custos-core-services/application.properties.j2,
+        dir: "Custos-Core-Services-Server-{{custos_distribution_version}}",
+        target: application.properties}
+    - { name: custos-core-services/bootstrap.properties.j2,
+        dir: "Custos-Core-Services-Server-{{custos_distribution_version}}",
+        target: bootstrap.properties }
+    - { name: custos-integration-services/application.properties.j2,
+        dir: "Custos-Integration-Services-Server-{{custos_distribution_version}}",
+        target: application.properties }
+  become: yes
+  become_user: "{{ user }}"
+
+- include: start_custos.yml
+
+- name: Start envoy proxy
+  script: "start_envoy_proxy.sh"
+  become: yes
+  become_user: "{{ user }}"
\ No newline at end of file
diff --git a/ansible/roles/custos/tasks/start_custos.yml b/ansible/roles/custos/tasks/start_custos.yml
new file mode 100644
index 000000000..74b9f9f27
--- /dev/null
+++ b/ansible/roles/custos/tasks/start_custos.yml
@@ -0,0 +1,49 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: Copy Custos systemd files
+  template: "src={{ item.name }}
+            dest=/etc/systemd/system/{{ item.target }}
+            owner={{ user }}
+            group={{ group }}
+            mode=\"u=rw,g=r,o=r\""
+  with_items:
+    - { name: corecustos.service.j2,
+        target: corecustos.service}
+    - { name: intcustos.service.j2,
+        target: intcustos.service}
+  become: yes
+
+- name: reload systemctl daemon
+  command: systemctl daemon-reload
+  become: yes
+
+- name: Start Custos Core service
+  service:
+    name: corecustos
+    state: restarted
+  become: yes
+
+- name: Start Custos Integration service
+  service:
+    name: intcustos
+    state: restarted
+  become: yes
\ No newline at end of file
diff --git a/ansible/roles/custos/templates/corecustos.service.j2 b/ansible/roles/custos/templates/corecustos.service.j2
new file mode 100644
index 000000000..6874f42c6
--- /dev/null
+++ b/ansible/roles/custos/templates/corecustos.service.j2
@@ -0,0 +1,13 @@
+[Unit]
+Description=Custos Core Service
+
+[Service]
+User={{ user }}
+Group={{ group }}
+ExecStart={{ custos_deployment_dir }}/Custos-Core-Services-Server-1.1-SNAPSHOT/bin/custos.sh
+Restart=always
+TimeoutSec=60
+Type=Forking
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/ansible/roles/custos/templates/custos-core-services/application.properties.j2 b/ansible/roles/custos/templates/custos-core-services/application.properties.j2
new file mode 100644
index 000000000..a8ef9615d
--- /dev/null
+++ b/ansible/roles/custos/templates/custos-core-services/application.properties.j2
@@ -0,0 +1,88 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+
+grpc.port={{ custos_core_grpc_port }}
+server.port={{ custos_core_server_port }}
+##spring.zipkin.baseUrl={{ custos_core_spring_zipkin_baseUrl }}
+spring.application.name={{ custos_core_spring_app_name }}
+##spring.sleuth.sampler.probability={{ custos_core_spring_sleuth_sampler_probability }}
+spring.main.allow-bean-definition-overriding={{ custos_core_spring_main_allow_bean_definition_overriding }}
+management.security.enabled={{ custos_core_management_security_enabled }}
+management.endpoints.web.exposure.include={{ custos_core_management_endpoints_web_exposure_include }}
+management.endpoint.metrics.enabled={{ custos_core_management_endpoint_metrics_enabled }}
+spring.jmx.enabled={{ custos_core_spring_jmx_enabled }}
+
+spring.datasource.url = {{ custos_core_spring_datasource_url }}
+spring.datasource.username = {{ custos_core_spring_datasource_username }}
+spring.datasource.password = {{ custos_core_spring_datasource_password }}
+
+## Hibernate Properties
+# The SQL dialect makes Hibernate generate better SQL for the chosen database
+spring.jpa.properties.hibernate.dialect = {{ custos_core_spring_jpa_properties_hibernate_dialect }}
+spring.jpa.properties.hibernate.enable_lazy_load_no_trans={{ custos_core_spring_jpa_properties_hibernate_enable_lazy_load_no_trans }}
+# Hibernate ddl auto (create, create-drop, validate, update)
+spring.jpa.hibernate.ddl-auto = {{ custos_core_spring_jpa_hibernate_ddl_auto }}
+spring.profiles.active={{ custos_core_spring_profiles_active }}
+logging.level.root={{ custos_core_logging_level_root }}
+
+ciLogon.admin.client.id={{ custos_core_ciLogon_admin_client_id }}
+ciLogon.admin.client.secret={{ custos_core_ciLogon_admin_client_secret }}
+ciLogon.admin.auth.endpoint={{ custos_core_ciLogon_admin_auth_endpoint }}
+
+iam.server.client.id={{ custos_core_iam_server_client_id }}
+iam.server.truststore.path={{ custos_core_iam_server_truststore_path }}
+iam.server.truststore.password={{ custos_core_iam_server_truststore_password }}
+iam.server.url={{ custos_core_iam_server_url }}
+iam.server.admin.username={{ custos_core_iam_server_admin_username }}
+iam.server.admin.password={{ custos_core_iam_server_admin_password }}
+iam.server.super.admin.realm.id={{ custos_core_iam_server_super_admin_realm_id }}
+iam.federated.cilogon.authorization.endpoint={{ custos_core_iam_federated_cilogon_authorization_endpoint }}
+iam.federated.cilogon.token.endpoint={{ custos_core_iam_federated_cilogon_token_endpoint }}
+iam.federated.cilogon.token.userinfo.endpoint={{ custos_core_iam_federated_cilogon_token_userinfo_endpoint }}
+iam.federated.cilogon.issuer={{ custos_core_iam_federated_cilogon_issuer }}
+iam.federated.cilogon.jwksUri={{ custos_core_iam_federated_cilogon_jwksUri }}
+introspection.endpoint={{ custos_core_introspection_endpoint }}
+issuer={{ custos_core_issuer }}
+authorization.endpoint={{ custos_core_authorization_endpoint }}
+token.endpoint={{ custos_core_token_endpoint }}
+end.session.endpoint={{ custos_core_end_session_endpoint }}
+user.info.endpoint={{ custos_core_user_info_endpoint }}
+jwks_uri={{ custos_core_jwks_uri }}
+registration.endpoint={{ custos_core_registration_endpoint }}
+cluster.management.core.service.dns.name={{ custos_core_cluster_management_core_service_dns_name }}
+cluster.management.core.service.port={{ custos_core_cluster_management_core_service_port }}
+
+core.services.server.hostname={{ custos_core_services_server_hostname }}
+core.services.server.port={{ custos_core_services_server_port }}
+
+custos.identity.auth.cache.enabled={{ custos_core_custos_identity_auth_cache_enabled }}
+custos.identity.auth.cache.size={{ custos_core_custos_identity_auth_cache_size }}
+
+core.messaging.service.broker.url={{ custos_core_core_messaging_service_broker_url }}
+core.messaging.service.publisher.id={{ custos_core_core_messaging_service_publisher_id }}
+mail.smtp.auth={{ custos_core_mail_smtp_auth }}
+mail.smtp.starttls.enable={{ custos_core_mail_smtp_starttls_enable }}
+mail.smtp.host={{ custos_core_mail_smtp_host }}
+mail.smtp.port={{ custos_core_mail_smtp_port }}
+mail.smtp.ssl.trust={{ custos_core_mail_smtp_ssl_trust }}
+mail.sender.username={{ custos_core_mail_sender_username }}
+mail.sender.password={{ custos_core_mail_sender_password }}
+
+user.profile.core.service.dns.name={{ custos_core_user_profile_core_service_dns_name }}
+user.profile.core.service.port={{ custos_core_user_profile_core_service_port }}
diff --git a/ansible/roles/custos/templates/custos-core-services/bootstrap.properties.j2 b/ansible/roles/custos/templates/custos-core-services/bootstrap.properties.j2
new file mode 100644
index 000000000..46b31a72f
--- /dev/null
+++ b/ansible/roles/custos/templates/custos-core-services/bootstrap.properties.j2
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+#  specific language governing permissions and limitations
+#  under the License
+
+spring.cloud.vault.token={{ vault_token }}
+spring.cloud.vault.scheme={{ vault_scheme }}
+spring.cloud.vault.host={{ vault_host }}
+spring.cloud.vault.port={{ vault_port }}
+spring.cloud.vault.uri={{ vault_uri }}
+spring.cloud.vault.authentication={{ spring_cloud_vault_authentication }}
+spring.cloud.vault.ssl.trust-store= {{ spring_cloud_vault_ssl_trust_store }}
+spring.cloud.vault.ssl.trust-store-password={{ spring_cloud_vault_ssl_truststore_password }}
diff --git a/ansible/roles/custos/templates/custos-core-services/config.yml.j2 b/ansible/roles/custos/templates/custos-core-services/config.yml.j2
new file mode 100644
index 000000000..e69de29bb
diff --git a/ansible/roles/custos/templates/custos-integration-services/application.properties.j2 b/ansible/roles/custos/templates/custos-integration-services/application.properties.j2
new file mode 100644
index 000000000..655d60a6d
--- /dev/null
+++ b/ansible/roles/custos/templates/custos-integration-services/application.properties.j2
@@ -0,0 +1,37 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+
+grpc.port={{ custos_int_grpc_port }}
+server.port={{ custos_int_server_port }}
+##spring.zipkin.baseUrl={{ custos_int_spring_zipkin_baseUrl }}
+spring.application.name={{ custos_int_spring_application_name }}
+##spring.sleuth.sampler.probability={{ custos_int_spring_sleuth_sampler_probability }}
+spring.main.allow-bean-definition-overriding={{ custos_int_spring_main_allow_bean_definition_overriding }}
+management.security.enabled={{ custos_int_management_security_enabled }}
+management.endpoints.web.exposure.include={{ custos_int_management_endpoints_web_exposure_include }}
+management.endpoint.metrics.enabled={{ custos_int_management_endpoint_metrics_enabled }}
+spring.jmx.enabled={{ custos_int_spring_jmx_enabled }}
+
+spring.profiles.active={{ custos_int_spring_profiles_active }}
+logging.level.root={{ custos_int_logging_level_root }}
+
+core.services.server.port={{ custos_int_core_services_server_port }}
+core.services.server.hostname={{ custos_int_core_services_server_hostname }}
+iam.server.url={{ custos_int_iam_server_url }}
+tenant.base.uri={{ custos_int_tenant_base_uri }}
\ No newline at end of file
diff --git a/ansible/roles/custos/templates/custos-integration-services/config.yml.j2 b/ansible/roles/custos/templates/custos-integration-services/config.yml.j2
new file mode 100644
index 000000000..e69de29bb
diff --git a/ansible/roles/custos/templates/intcustos.service.j2 b/ansible/roles/custos/templates/intcustos.service.j2
new file mode 100644
index 000000000..a7f257604
--- /dev/null
+++ b/ansible/roles/custos/templates/intcustos.service.j2
@@ -0,0 +1,13 @@
+[Unit]
+Description=Custos Integration Service
+
+[Service]
+User={{ user }}
+Group={{ group }}
+ExecStart={{ custos_deployment_dir }}/Custos-Integration-Services-Server-1.1-SNAPSHOT/bin/custos.sh
+Restart=always
+TimeoutSec=60
+Type=Forking
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/ansible/roles/database/tasks/import_db.yml b/ansible/roles/database/tasks/import_db.yml
new file mode 100644
index 000000000..eab56767e
--- /dev/null
+++ b/ansible/roles/database/tasks/import_db.yml
@@ -0,0 +1,31 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: Copy dump file from master node to new server
+  copy:
+    src: tmp/core_services_server_db_arch.sql
+    dest: /home/exouser/backups/
+
+- name: import dump file to mysql
+  mysql_db:
+    name: core_services_server_db
+    state: import
+    target: /home/exouser/backups/core_services_server_db_arch.sql
diff --git a/ansible/roles/database/tasks/main.yml b/ansible/roles/database/tasks/main.yml
new file mode 100644
index 000000000..81093c413
--- /dev/null
+++ b/ansible/roles/database/tasks/main.yml
@@ -0,0 +1,47 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: Install MySQL
+  apt:
+    name:
+    - mysql-server
+    - python3-pymysql
+  become: yes
+
+- name: Start the MySQL service
+  service:
+    name: mysql
+    state: started
+    enabled: yes
+
+- name: Set up MySQL
+  include_tasks: secure_install.yml
+
+- name: Create a new database with name "{{ db_name }}"
+  community.mysql.mysql_db:
+    name: "{{ db_name }}"
+    state: present
+    encoding: "UTF8mb3"
+    collation: "utf8_general_ci"
+
+- name: Import old server's dump file
+  include_tasks: import_db.yml
+  tags: [never, migrate_db]
diff --git a/ansible/roles/database/tasks/secure_install.yml b/ansible/roles/database/tasks/secure_install.yml
new file mode 100644
index 000000000..619884102
--- /dev/null
+++ b/ansible/roles/database/tasks/secure_install.yml
@@ -0,0 +1,51 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+
+# The following works but its not idemmpotent
+- name: Set password for root user
+  mysql_user:
+    # you can get socket path from /etc/mysql/mysql.conf.d/mysqld.cnf
+    check_implicit_admin: yes
+    login_unix_socket: /var/run/mysqld/mysqld.sock  # default path
+    login_user: root
+    login_password: "{{ custos_core_spring_datasource_password }}"
+    name: root
+    password: "{{ custos_core_spring_datasource_password }}"
+    priv: '*.*:ALL,GRANT'
+    host: 'localhost'
+    state: present
+  become: yes
+
+- name: Copy .my.cnf file
+  template: src=my.cnf.j2 dest="{{ user_home }}/.my.cnf"
+  # become: yes
+
+- name: Removes all anonymous user accounts
+  mysql_user: name='' host_all=yes state=absent login_password="{{ custos_core_spring_datasource_password }}"
+
+- name: Secures the MySQL root user for all hosts
+  mysql_user: user=root login_password="{{ custos_core_spring_datasource_password }}" host_all=yes
+
+- name: Removes the MySQL test database
+  mysql_db: db=test state=absent login_password="{{ custos_core_spring_datasource_password }}"
+
+...
diff --git a/ansible/roles/database/templates/my.cnf.j2 b/ansible/roles/database/templates/my.cnf.j2
new file mode 100644
index 000000000..79d0c8bf6
--- /dev/null
+++ b/ansible/roles/database/templates/my.cnf.j2
@@ -0,0 +1,4 @@
+# Example .my.cnf file for setting the root password
+[client]
+user=root
+password="{{ custos_core_spring_datasource_password }}"
diff --git a/ansible/roles/env_setup/handlers/main.yml b/ansible/roles/env_setup/handlers/main.yml
new file mode 100644
index 000000000..d99835134
--- /dev/null
+++ b/ansible/roles/env_setup/handlers/main.yml
@@ -0,0 +1,25 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: restart nginx
+  service:
+    name: nginx
+    state: restarted
\ No newline at end of file
diff --git a/ansible/roles/env_setup/tasks/main.yml b/ansible/roles/env_setup/tasks/main.yml
new file mode 100644
index 000000000..20d457d01
--- /dev/null
+++ b/ansible/roles/env_setup/tasks/main.yml
@@ -0,0 +1,123 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: apt-get update
+  apt:
+    update_cache: yes
+    cache_valid_time: 86400
+  become: yes
+
+- name: install nginx
+  apt:
+    name: nginx
+    state: latest
+  become: yes
+
+- name: allow OpenSSH
+  ufw:
+    rule: allow
+    name: "OpenSSH"
+    state: enabled
+  become: yes
+
+# It is recommended to enable the most restrictive profile
+#  that will still allow the traffic you’ve configured.
+#  Right now, we will only need to allow traffic on port 80.
+- name: allow traffic on port 80
+  ufw:
+    rule: allow
+    name: "Nginx HTTP"
+    state: enabled # enable the ufw rule
+  become: yes
+
+- name: create www directory at "/var/www/{{ ansible_host }}"
+  file:
+    path: /var/www/{{ ansible_host }}
+    state: directory
+    mode: '0775'
+    owner: "{{ user }}"
+    group: "{{ group }}"
+  become: yes
+
+- name: copy sample index.html from {{ inventory_hostname }} to /var/www/{{ ansible_host }}/html
+  template: >
+    src={{ inventory_hostname }}/index.html.j2
+    dest="/var/www/{{ ansible_host }}/index.html"
+    owner="{{ user }}"
+    group="{{ group }}"
+    mode="u=rw,g=r,o=r"
+
+- name: delete default nginx config
+  file:
+    path: /etc/nginx/sites-enabled/default
+    state: absent
+  become: yes
+
+- name: copy default nginx site.conf
+  template:
+    src: "{{ inventory_hostname }}/default_site.conf.j2"
+    dest: /etc/nginx/sites-available/{{ ansible_host }}
+    owner: root
+    group: root
+    mode: '0644'
+  become: yes
+
+- name: link sample html to sites-enabled directory
+  file:
+    src: /etc/nginx/sites-available/{{ ansible_host }}
+    dest: /etc/nginx/sites-enabled/{{ ansible_host }}
+    state: link
+  become: yes
+
+- name: allow HTTPS traffic
+  ufw:
+    rule: allow
+    name: "Nginx Full"
+    state: enabled # enable the ufw rule
+  become: yes
+
+- name: delete redundant Nginx HTTP
+  ufw:
+    rule: allow
+    name: "Nginx HTTP"
+    delete: yes
+    state: enabled # enable the ufw rule
+  become: yes
+
+- name: Restart nginx
+  service:
+    name: nginx
+    state: restarted
+  become: yes
+
+- name: install certbot
+  apt:
+    name:
+      - certbot
+      - python3-certbot-nginx
+    state: latest
+  become: yes
+
+- name: Create certs directory
+  ansible.builtin.file:
+    path: "{{ user_home }}/certs"
+    state: directory
+    mode: '0755'
\ No newline at end of file
diff --git a/ansible/roles/env_setup/templates/custos/default_site.conf.j2 b/ansible/roles/env_setup/templates/custos/default_site.conf.j2
new file mode 100644
index 000000000..53fa29b1b
--- /dev/null
+++ b/ansible/roles/env_setup/templates/custos/default_site.conf.j2
@@ -0,0 +1,11 @@
+server {
+  listen 80;
+  listen [::]:80;
+
+  root /var/www/{{ ansible_host }}/html;
+  index index.html index.htm index.nginx-debian.html;
+  server_name {{ ansible_host }} www.{{ ansible_host }};
+  location / {
+    try_files $uri $uri/ =404;
+  }
+}
\ No newline at end of file
diff --git a/ansible/roles/env_setup/templates/custos/index.html.j2 b/ansible/roles/env_setup/templates/custos/index.html.j2
new file mode 100644
index 000000000..da5a6b58a
--- /dev/null
+++ b/ansible/roles/env_setup/templates/custos/index.html.j2
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>Welcome to your_domain!</title>
+    </head>
+    <body>
+        <h1>Success!  The your_domain server block is working!</h1>
+    </body>
+</html>
\ No newline at end of file
diff --git a/ansible/roles/env_setup/templates/custos/nginx.conf.j2 b/ansible/roles/env_setup/templates/custos/nginx.conf.j2
new file mode 100644
index 000000000..706278c7c
--- /dev/null
+++ b/ansible/roles/env_setup/templates/custos/nginx.conf.j2
@@ -0,0 +1,85 @@
+user www-data;
+worker_processes auto;
+pid /run/nginx.pid;
+include /etc/nginx/modules-enabled/*.conf;
+
+events {
+	worker_connections 768;
+	# multi_accept on;
+}
+
+http {
+
+	##
+	# Basic Settings
+	##
+
+	sendfile on;
+	tcp_nopush on;
+	tcp_nodelay on;
+	keepalive_timeout 65;
+	types_hash_max_size 2048;
+	# server_tokens off;
+
+	server_names_hash_bucket_size 64;
+	# server_name_in_redirect off;
+
+	include /etc/nginx/mime.types;
+	default_type application/octet-stream;
+
+	##
+	# SSL Settings
+	##
+
+	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
+	ssl_prefer_server_ciphers on;
+
+	##
+	# Logging Settings
+	##
+
+	access_log /var/log/nginx/access.log;
+	error_log /var/log/nginx/error.log;
+
+	##
+	# Gzip Settings
+	##
+
+	gzip on;
+
+	# gzip_vary on;
+	# gzip_proxied any;
+	# gzip_comp_level 6;
+	# gzip_buffers 16 8k;
+	# gzip_http_version 1.1;
+	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+	##
+	# Virtual Host Configs
+	##
+
+	include /etc/nginx/conf.d/*.conf;
+	include /etc/nginx/sites-enabled/*;
+}
+
+
+#mail {
+#	# See sample authentication script at:
+#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
+#
+#	# auth_http localhost/auth.php;
+#	# pop3_capabilities "TOP" "USER";
+#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
+#
+#	server {
+#		listen     localhost:110;
+#		protocol   pop3;
+#		proxy      on;
+#	}
+#
+#	server {
+#		listen     localhost:143;
+#		protocol   imap;
+#		proxy      on;
+#	}
+#}
diff --git a/ansible/roles/env_setup/templates/hashicorp/default_site.conf.j2 b/ansible/roles/env_setup/templates/hashicorp/default_site.conf.j2
new file mode 100644
index 000000000..53fa29b1b
--- /dev/null
+++ b/ansible/roles/env_setup/templates/hashicorp/default_site.conf.j2
@@ -0,0 +1,11 @@
+server {
+  listen 80;
+  listen [::]:80;
+
+  root /var/www/{{ ansible_host }}/html;
+  index index.html index.htm index.nginx-debian.html;
+  server_name {{ ansible_host }} www.{{ ansible_host }};
+  location / {
+    try_files $uri $uri/ =404;
+  }
+}
\ No newline at end of file
diff --git a/ansible/roles/env_setup/templates/hashicorp/index.html.j2 b/ansible/roles/env_setup/templates/hashicorp/index.html.j2
new file mode 100644
index 000000000..a557e65cd
--- /dev/null
+++ b/ansible/roles/env_setup/templates/hashicorp/index.html.j2
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>Welcome to {{ inventory_hostname }}!</title>
+    </head>
+    <body>
+        <h1>Success!  The {{ inventory_hostname }} server block is working!</h1>
+    </body>
+</html>
\ No newline at end of file
diff --git a/ansible/roles/env_setup/templates/hashicorp/nginx.conf.j2 b/ansible/roles/env_setup/templates/hashicorp/nginx.conf.j2
new file mode 100644
index 000000000..706278c7c
--- /dev/null
+++ b/ansible/roles/env_setup/templates/hashicorp/nginx.conf.j2
@@ -0,0 +1,85 @@
+user www-data;
+worker_processes auto;
+pid /run/nginx.pid;
+include /etc/nginx/modules-enabled/*.conf;
+
+events {
+	worker_connections 768;
+	# multi_accept on;
+}
+
+http {
+
+	##
+	# Basic Settings
+	##
+
+	sendfile on;
+	tcp_nopush on;
+	tcp_nodelay on;
+	keepalive_timeout 65;
+	types_hash_max_size 2048;
+	# server_tokens off;
+
+	server_names_hash_bucket_size 64;
+	# server_name_in_redirect off;
+
+	include /etc/nginx/mime.types;
+	default_type application/octet-stream;
+
+	##
+	# SSL Settings
+	##
+
+	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
+	ssl_prefer_server_ciphers on;
+
+	##
+	# Logging Settings
+	##
+
+	access_log /var/log/nginx/access.log;
+	error_log /var/log/nginx/error.log;
+
+	##
+	# Gzip Settings
+	##
+
+	gzip on;
+
+	# gzip_vary on;
+	# gzip_proxied any;
+	# gzip_comp_level 6;
+	# gzip_buffers 16 8k;
+	# gzip_http_version 1.1;
+	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+	##
+	# Virtual Host Configs
+	##
+
+	include /etc/nginx/conf.d/*.conf;
+	include /etc/nginx/sites-enabled/*;
+}
+
+
+#mail {
+#	# See sample authentication script at:
+#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
+#
+#	# auth_http localhost/auth.php;
+#	# pop3_capabilities "TOP" "USER";
+#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
+#
+#	server {
+#		listen     localhost:110;
+#		protocol   pop3;
+#		proxy      on;
+#	}
+#
+#	server {
+#		listen     localhost:143;
+#		protocol   imap;
+#		proxy      on;
+#	}
+#}
diff --git a/ansible/roles/env_setup/templates/keycloak/default_site.conf.j2 b/ansible/roles/env_setup/templates/keycloak/default_site.conf.j2
new file mode 100644
index 000000000..299c12429
--- /dev/null
+++ b/ansible/roles/env_setup/templates/keycloak/default_site.conf.j2
@@ -0,0 +1,8 @@
+upstream keycloak {
+  server localhost:8080 ;
+}
+server {
+   listen 80;
+   server_name bm-dev-2.usecustos.org;
+   return 301 https://bm-dev-2.usecustos.org$request_uri;
+}
\ No newline at end of file
diff --git a/ansible/roles/env_setup/templates/keycloak/index.html.j2 b/ansible/roles/env_setup/templates/keycloak/index.html.j2
new file mode 100644
index 000000000..da5a6b58a
--- /dev/null
+++ b/ansible/roles/env_setup/templates/keycloak/index.html.j2
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>Welcome to your_domain!</title>
+    </head>
+    <body>
+        <h1>Success!  The your_domain server block is working!</h1>
+    </body>
+</html>
\ No newline at end of file
diff --git a/ansible/roles/env_setup/templates/keycloak/nginx.conf.j2 b/ansible/roles/env_setup/templates/keycloak/nginx.conf.j2
new file mode 100644
index 000000000..706278c7c
--- /dev/null
+++ b/ansible/roles/env_setup/templates/keycloak/nginx.conf.j2
@@ -0,0 +1,85 @@
+user www-data;
+worker_processes auto;
+pid /run/nginx.pid;
+include /etc/nginx/modules-enabled/*.conf;
+
+events {
+	worker_connections 768;
+	# multi_accept on;
+}
+
+http {
+
+	##
+	# Basic Settings
+	##
+
+	sendfile on;
+	tcp_nopush on;
+	tcp_nodelay on;
+	keepalive_timeout 65;
+	types_hash_max_size 2048;
+	# server_tokens off;
+
+	server_names_hash_bucket_size 64;
+	# server_name_in_redirect off;
+
+	include /etc/nginx/mime.types;
+	default_type application/octet-stream;
+
+	##
+	# SSL Settings
+	##
+
+	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
+	ssl_prefer_server_ciphers on;
+
+	##
+	# Logging Settings
+	##
+
+	access_log /var/log/nginx/access.log;
+	error_log /var/log/nginx/error.log;
+
+	##
+	# Gzip Settings
+	##
+
+	gzip on;
+
+	# gzip_vary on;
+	# gzip_proxied any;
+	# gzip_comp_level 6;
+	# gzip_buffers 16 8k;
+	# gzip_http_version 1.1;
+	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+	##
+	# Virtual Host Configs
+	##
+
+	include /etc/nginx/conf.d/*.conf;
+	include /etc/nginx/sites-enabled/*;
+}
+
+
+#mail {
+#	# See sample authentication script at:
+#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
+#
+#	# auth_http localhost/auth.php;
+#	# pop3_capabilities "TOP" "USER";
+#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
+#
+#	server {
+#		listen     localhost:110;
+#		protocol   pop3;
+#		proxy      on;
+#	}
+#
+#	server {
+#		listen     localhost:143;
+#		protocol   imap;
+#		proxy      on;
+#	}
+#}
diff --git a/ansible/roles/kafka/defaults/main.yml b/ansible/roles/kafka/defaults/main.yml
new file mode 100644
index 000000000..0b99e0e38
--- /dev/null
+++ b/ansible/roles/kafka/defaults/main.yml
@@ -0,0 +1,43 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+
+kafka_package_name: "confluent-5.3.1"
+kafka_tgz_url: "http://packages.confluent.io/archive/5.3/confluent-5.3.1-2.12.zip"
+kafka_dir: "{{ custos_deployment_dir }}/{{ kafka_package_name }}"
+kafka_rest_proxy_listener_port: 8082
+
+broker_id: "0"
+network_threads_count: "3"
+io_threads_count: "8"
+socket_send_buf_bytes: "102400"
+socket_receive_buf_bytes: "102400"
+socket_request_max_bytes: "104857600"
+num_partitions: "1"
+num_recovery_threads: "1"
+offsets_topic_replication_fac: "1"
+trans_state_log_replication_fac: "1"
+trans_state_log: "1"
+log_retention_hrs: "168"
+log_segment_bytes: "1073741824"
+log_retention_check_interval: "300000"
+grp_initial_rebalance_delay: "0"
+kafka_listener_port: 9092
diff --git a/ansible/roles/kafka/handlers/main.yml b/ansible/roles/kafka/handlers/main.yml
new file mode 100644
index 000000000..985698998
--- /dev/null
+++ b/ansible/roles/kafka/handlers/main.yml
@@ -0,0 +1,45 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+# Kafka related handlers
+- name: start kafka
+  service: name=kafka state=started enabled=yes
+  become: yes
+
+- name: stop kafka
+  service: name=kafka state=stopped enabled=yes
+  become: yes
+
+- name: restart kafka
+  service: name=kafka state=restarted enabled=yes
+  become: yes
+
+- name: start kafka-rest-proxy
+  service: name=kafka-rest-proxy state=started enabled=yes
+  become: yes
+
+- name: stop kafka-rest-proxy
+  service: name=kafka-rest-proxy state=stopped enabled=yes
+  become: yes
+
+- name: restart kafka-rest-proxy
+  service: name=kafka-rest-proxy state=restarted enabled=yes
+  become: yes
diff --git a/ansible/roles/kafka/tasks/main.yml b/ansible/roles/kafka/tasks/main.yml
new file mode 100644
index 000000000..43fb6f6a5
--- /dev/null
+++ b/ansible/roles/kafka/tasks/main.yml
@@ -0,0 +1,139 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+
+# Check for the availability of the Kafka package
+- name: Check kafka package availability
+  stat: path={{ kafka_dir }}
+  register: kafka_package
+  become: yes
+
+- name: Create deployment directory {{ custos_deployment_dir }}
+  file: path={{custos_deployment_dir}}
+    state=directory
+    mode=0755
+    owner={{ user }}
+    group={{ group }}
+  become: yes
+
+# Download Kafka
+- name: Download and unarchive Kafka from {{ kafka_tgz_url }}
+  unarchive: src="{{ kafka_tgz_url }}"
+    dest="{{ custos_deployment_dir }}"
+    copy=no
+    owner="{{ user }}"
+    group="{{ group }}"
+  when: not kafka_package.stat.exists
+  become: yes
+
+# Create kafka logs directory
+- name: Create kafka logs directory
+  file: path="{{ kafka_dir }}/logs" state=directory owner={{ user }} group={{ group }}
+  become: yes
+
+
+# Config kafka server and start
+- name: Copy kafka server properties file
+  template: src=server.properties.j2
+    dest="{{ kafka_dir }}/etc/kafka/server.properties"
+    owner={{ user }}
+    group={{ group }}
+    mode="u=rw,g=r,o=r"
+#  notify: restart kafka
+  become: yes
+
+# Config rest proxy and start
+- name: Copy kafka rest proxy properties file
+  template: src=kafka-rest.properties.j2
+    dest="{{ kafka_dir }}/etc/kafka-rest/kafka-rest.properties"
+    owner={{ user }}
+    group={{ group }}
+    mode="u=rw,g=r,o=r"
+  become: yes
+
+#- name: uninstall firewalld # install firewalld
+#  apt:
+#    name: firewalld
+#    state: absent #latest
+#  become: yes
+
+#- name: start firewalld #and python-firewall
+#  service: name=firewalld state=started
+#  become: yes
+
+#- name: open kafka proxy port
+#  firewalld:
+#    zone: public
+#    permanent: yes
+#    state: enabled
+#    immediate: yes
+#    rich_rule: rule family=ipv4 source address="{{ item }}" port port="{{ kafka_listener_port }}" protocol=tcp accept
+#  become: yes
+#  with_items:
+#    - "{{ sharing_subnets }}"
+#
+#- name: open kafka rest proxy port
+#  firewalld:
+#    zone: public
+#    permanent: yes
+#    state: enabled
+#    immediate: yes
+#    rich_rule: rule family=ipv4 source address="{{ item }}" port port="{{ kafka_rest_proxy_listener_port }}" protocol=tcp accept
+#  become: yes
+#  with_items:
+#    - "{{ sharing_subnets }}"
+
+- name: systemd install kafka service script
+  template: src=kafka.service.j2
+    dest=/usr/lib/systemd/system/kafka.service
+    owner={{ user }}
+    group={{ group }}
+    mode="u=rw,g=r,o=r"
+#  notify: start kafka
+  become: yes
+
+- name: systemd install kafka rest proxy service script
+  template: src=kafka-rest-proxy.service.j2
+    dest=/usr/lib/systemd/system/kafka-rest-proxy.service
+    owner={{ user }}
+    group={{ group }}
+    mode="u=rw,g=r,o=r"
+  become: yes
+
+- name: Reload systemd daemons
+  command: systemctl daemon-reload
+#  notify: restart kafka
+  become: yes
+
+- name: Reload systemd daemons
+  command: systemctl daemon-reload
+#  notify: restart kafka-rest-proxy
+  become: yes
+
+- name: restart kafka
+  service: name=kafka state=restarted enabled=yes
+  become: yes
+
+- name: restart kafka-rest-proxy
+  service: name=kafka-rest-proxy state=restarted enabled=yes
+  become: yes
+
+...
diff --git a/ansible/roles/kafka/templates/kafka-rest-proxy.service.j2 b/ansible/roles/kafka/templates/kafka-rest-proxy.service.j2
new file mode 100644
index 000000000..338de9f26
--- /dev/null
+++ b/ansible/roles/kafka/templates/kafka-rest-proxy.service.j2
@@ -0,0 +1,14 @@
+# {{ansible_managed}}
+
+[Unit]
+Description=Kafka-Rest-Proxy
+Before=
+After=network.target
+
+[Service]
+LOG_DIR={{ kafka_dir }}/logs
+ExecStart={{ kafka_dir }}/bin/kafka-rest-start {{ kafka_dir }}/etc/kafka-rest/kafka-rest.properties
+Restart=on-abort
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/ansible/roles/kafka/templates/kafka-rest.properties.j2 b/ansible/roles/kafka/templates/kafka-rest.properties.j2
new file mode 100644
index 000000000..a512daa6e
--- /dev/null
+++ b/ansible/roles/kafka/templates/kafka-rest.properties.j2
@@ -0,0 +1,25 @@
+#
+# Copyright 2018 Confluent Inc.
+#
+# Licensed under the Confluent Community License (the "License"); you may not use
+# this file except in compliance with the License.  You may obtain a copy of the
+# License at
+#
+# http://www.confluent.io/confluent-community-license
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+#id=kafka-rest-test-server
+#schema.registry.url=http://localhost:8081
+#zookeeper.connect=localhost:2181
+bootstrap.servers=PLAINTEXT://{{ kafka_url }}
+listeners=http://{{ ansible_default_ipv4.address }}:{{ kafka_rest_proxy_listener_port }}
+#
+# Configure interceptor classes for sending consumer and producer metrics to Confluent Control Center
+# Make sure that monitoring-interceptors-<version>.jar is on the Java class path
+#consumer.interceptor.classes=io.confluent.monitoring.clients.interceptor.MonitoringConsumerInterceptor
+#producer.interceptor.classes=io.confluent.monitoring.clients.interceptor.MonitoringProducerInterceptor
diff --git a/ansible/roles/kafka/templates/kafka.service.j2 b/ansible/roles/kafka/templates/kafka.service.j2
new file mode 100644
index 000000000..afc011854
--- /dev/null
+++ b/ansible/roles/kafka/templates/kafka.service.j2
@@ -0,0 +1,14 @@
+# {{ansible_managed}}
+
+[Unit]
+Description=Kafka
+Before=
+After=network.target
+
+[Service]
+LOG_DIR={{ kafka_dir }}/logs
+ExecStart={{ kafka_dir }}/bin/kafka-server-start {{ kafka_dir }}/etc/kafka/server.properties
+Restart=on-abort
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/ansible/roles/kafka/templates/server.properties.j2 b/ansible/roles/kafka/templates/server.properties.j2
new file mode 100644
index 000000000..7498aa0ce
--- /dev/null
+++ b/ansible/roles/kafka/templates/server.properties.j2
@@ -0,0 +1,201 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# see kafka.server.KafkaConfig for additional details and defaults
+
+############################# Server Basics #############################
+
+# The id of the broker. This must be set to a unique integer for each broker.
+broker.id={{ broker_id }}
+
+############################# Socket Server Settings #############################
+
+# The address the socket server listens on. It will get the value returned from
+# java.net.InetAddress.getCanonicalHostName() if not configured.
+#   FORMAT:
+#     listeners = listener_name://host_name:port
+#   EXAMPLE:
+#     listeners = PLAINTEXT://your.host.name:9092
+#listeners=PLAINTEXT://0.0.0.0:{{ kafka_listener_port }}
+
+# Hostname and port the broker will advertise to producers and consumers. If not set,
+# it uses the value for "listeners" if configured.  Otherwise, it will use the value
+# returned from java.net.InetAddress.getCanonicalHostName().
+#advertised.listeners=PLAINTEXT://{{ kafka_url }}
+
+# Maps listener names to security protocols, the default is for them to be the same. See the config documentation for more details
+#listener.security.protocol.map=PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL
+
+# The number of threads that the server uses for receiving requests from the network and sending responses to the network
+num.network.threads={{ network_threads_count }}
+
+# The number of threads that the server uses for processing requests, which may include disk I/O
+num.io.threads={{ io_threads_count }}
+
+# The send buffer (SO_SNDBUF) used by the socket server
+socket.send.buffer.bytes={{ socket_send_buf_bytes }}
+
+# The receive buffer (SO_RCVBUF) used by the socket server
+socket.receive.buffer.bytes={{ socket_receive_buf_bytes }}
+
+# The maximum size of a request that the socket server will accept (protection against OOM)
+socket.request.max.bytes={{ socket_request_max_bytes }}
+
+
+############################# Log Basics #############################
+
+# A comma separated list of directories under which to store log files
+log.dirs={{ kafka_dir }}/logs
+
+# The default number of log partitions per topic. More partitions allow greater
+# parallelism for consumption, but this will also result in more files across
+# the brokers.
+num.partitions={{ num_partitions }}
+
+# The number of threads per data directory to be used for log recovery at startup and flushing at shutdown.
+# This value is recommended to be increased for installations with data dirs located in RAID array.
+num.recovery.threads.per.data.dir={{ num_recovery_threads }}
+
+############################# Internal Topic Settings  #############################
+# The replication factor for the group metadata internal topics "__consumer_offsets" and "__transaction_state"
+# For anything other than development testing, a value greater than 1 is recommended for to ensure availability such as 3.
+offsets.topic.replication.factor={{ offsets_topic_replication_fac }}
+transaction.state.log.replication.factor={{ trans_state_log_replication_fac }}
+transaction.state.log.min.isr={{ trans_state_log }}
+
+############################# Log Flush Policy #############################
+
+# Messages are immediately written to the filesystem but by default we only fsync() to sync
+# the OS cache lazily. The following configurations control the flush of data to disk.
+# There are a few important trade-offs here:
+#    1. Durability: Unflushed data may be lost if you are not using replication.
+#    2. Latency: Very large flush intervals may lead to latency spikes when the flush does occur as there will be a lot of data to flush.
+#    3. Throughput: The flush is generally the most expensive operation, and a small flush interval may lead to excessive seeks.
+# The settings below allow one to configure the flush policy to flush data after a period of time or
+# every N messages (or both). This can be done globally and overridden on a per-topic basis.
+
+# The number of messages to accept before forcing a flush of data to disk
+#log.flush.interval.messages=10000
+
+# The maximum amount of time a message can sit in a log before we force a flush
+#log.flush.interval.ms=1000
+
+############################# Log Retention Policy #############################
+
+# The following configurations control the disposal of log segments. The policy can
+# be set to delete segments after a period of time, or after a given size has accumulated.
+# A segment will be deleted whenever *either* of these criteria are met. Deletion always happens
+# from the end of the log.
+
+# The minimum age of a log file to be eligible for deletion due to age
+log.retention.hours={{ log_retention_hrs }}
+
+# A size-based retention policy for logs. Segments are pruned from the log unless the remaining
+# segments drop below log.retention.bytes. Functions independently of log.retention.hours.
+#log.retention.bytes=1073741824
+
+# The maximum size of a log segment file. When this size is reached a new log segment will be created.
+log.segment.bytes={{ log_segment_bytes }}
+
+# The interval at which log segments are checked to see if they can be deleted according
+# to the retention policies
+log.retention.check.interval.ms={{ log_retention_check_interval }}
+
+############################# Zookeeper #############################
+
+# Zookeeper connection string (see zookeeper docs for details).
+# This is a comma separated host:port pairs, each corresponding to a zk
+# server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002".
+# You can also append an optional chroot string to the urls to specify the
+# root directory for all kafka znodes.
+zookeeper.connect={{ zookeeper_connection_url }}
+
+# Timeout in ms for connecting to zookeeper
+zookeeper.connection.timeout.ms={{ zookeeper_connection_timeout }}
+
+##################### Confluent Metrics Reporter #######################
+# Confluent Control Center and Confluent Auto Data Balancer integration
+#
+# Uncomment the following lines to publish monitoring data for
+# Confluent Control Center and Confluent Auto Data Balancer
+# If you are using a dedicated metrics cluster, also adjust the settings
+# to point to your metrics kakfa cluster.
+#metric.reporters=io.confluent.metrics.reporter.ConfluentMetricsReporter
+#confluent.metrics.reporter.bootstrap.servers=localhost:9092
+#
+# Uncomment the following line if the metrics cluster has a single broker
+#confluent.metrics.reporter.topic.replicas=1
+
+##################### Confluent Proactive Support ######################
+# If set to true, and confluent-support-metrics package is installed
+# then the feature to collect and report support metrics
+# ("Metrics") is enabled.  If set to false, the feature is disabled.
+#
+confluent.support.metrics.enable=true
+
+
+# The customer ID under which support metrics will be collected and
+# reported.
+#
+# When the customer ID is set to "anonymous" (the default), then only a
+# reduced set of metrics is being collected and reported.
+#
+# Confluent customers
+# -------------------
+# If you are a Confluent customer, then you should replace the default
+# value with your actual Confluent customer ID.  Doing so will ensure
+# that additional support metrics will be collected and reported.
+#
+confluent.support.customer.id=anonymous
+
+############################# Group Coordinator Settings #############################
+
+# The following configuration specifies the time, in milliseconds, that the GroupCoordinator will delay the initial consumer rebalance.
+# The rebalance will be further delayed by the value of group.initial.rebalance.delay.ms as new members join the group, up to a maximum of max.poll.interval.ms.
+# The default value for this is 3 seconds.
+# We override this to 0 here as it makes for a better out-of-the-box experience for development and testing.
+# However, in production environments the default value of 3 seconds is more suitable as this will help to avoid unnecessary, and potentially expensive, rebalances during application startup.
+group.initial.rebalance.delay.ms={{ grp_initial_rebalance_delay }}
+
+
+############################# Confluent Authorizer Settings  #############################
+
+# Uncomment to enable Confluent Authorizer with support for ACLs, LDAP groups and RBAC
+#authorizer.class.name=io.confluent.kafka.security.authorizer.ConfluentServerAuthorizer
+# Semi-colon separated list of super users in the format <principalType>:<principalName>
+#super.users=
+# Specify a valid Confluent license. By default free-tier license will be used
+#confluent.license=
+# Replication factor for the topic used for licensing. Default is 3.
+confluent.license.topic.replication.factor=1
+
+# Uncomment the following lines and specify values where required to enable RBAC
+# Enable RBAC provider
+#confluent.authorizer.access.rule.providers=ACL,RBAC
+# Bootstrap servers for RBAC metadata. Must be provided if this broker is not in the metadata cluster
+#confluent.metadata.bootstrap.servers=PLAINTEXT://127.0.0.1:9092
+# Replication factor for the metadata topic used for authorization. Default is 3.
+confluent.metadata.topic.replication.factor=1
+
+# Listeners for metadata server
+#confluent.metadata.server.listeners=http://0.0.0.0:8090
+# Advertised listeners for metadata server
+#confluent.metadata.server.advertised.listeners=http://127.0.0.1:8090
+
+############################# Additional fixes #######################
+delete.topic.enable = true
+auto.create.topics.enable=true
+# listeners=PLAINTEXT://0.0.0.0:9092
+advertised.listeners = PLAINTEXT://{{ ansible_host }}:9092
diff --git a/ansible/roles/keycloak/README.md b/ansible/roles/keycloak/README.md
new file mode 100644
index 000000000..42f6bd978
--- /dev/null
+++ b/ansible/roles/keycloak/README.md
@@ -0,0 +1,12 @@
+## Keycloak Deployment
+
+###Configuration variables are distributed between :
+1. `roles/keycloak/default/main.yml` - defaults for keycloak internal variables
+2. `inventories/airavata-iam/group_vars/all.yml` - Global variables
+
+###Running instructions:
+
+1. Make sure all the variables are configured correctly
+2. Dont use the Database role, rather set up the VM with default version provided by centos, tested with MySql 5.6 & MariaDB 5.5.52), Ansible role for the same is coming soon.
+3. Ensure the host file: `inventories/airavata-iam/hosts` has correct IP address
+4. For Standalone mode deployment : `ansible-playbook -i inventories/airavata-iam keycloak.yml`
diff --git a/ansible/roles/keycloak/defaults/main.yml b/ansible/roles/keycloak/defaults/main.yml
new file mode 100644
index 000000000..605761737
--- /dev/null
+++ b/ansible/roles/keycloak/defaults/main.yml
@@ -0,0 +1,45 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+keycloak_version: "20.0.1"
+keycloak_downlaod_url: "https://downloads.jboss.org/keycloak/{{keycloak_version}}/keycloak-{{keycloak_version}}.tar.gz"
+keycloak_install_dir: "keycloak-{{keycloak_version}}"
+keycloak_db_connector_name: "mysql-connector-java-5.1.41"
+# keycloak_ssl_keystore_file: "keycloak.jks"
+# keycloak_ssl_keystore_file_name: "keycloak.jks"
+# keycloak_ssl_keystore_password: "Airavata"
+mysql_db_connector_download_url: "https://dev.mysql.com/get/Downloads/Connector-J/{{keycloak_db_connector_name}}.tar.gz"
+keycloak_master_account_username: "username"
+keycloak_master_account_password: "password"
+# keycloak_server_port: "443"
+
+keycloak_db_host: "localhost"
+keycloak_db_schema_name: "postgresDB"
+keycloak_db_url: "jdbc:postgresql://{{keycloak_db_host}}/{{keycloak_db_schema_name}}"
+keycloak_db_username: "postgres"
+keycloak_db_password: "postgres"
+keycloak_db_pool_size: "20"
+
+keycloak_vhost_servername: "changeme.org"
+keycloak_ssl_certificate_file: "/etc/letsencrypt/live/{{ keycloak_vhost_servername }}/cert.pem"
+keycloak_ssl_certificate_chain_file: "/etc/letsencrypt/live/{{ keycloak_vhost_servername }}/fullchain.pem"
+keycloak_ssl_certificate_key_file: "/etc/letsencrypt/live/{{ keycloak_vhost_servername }}/privkey.pem"
+...
diff --git a/ansible/roles/keycloak/handlers/main.yml b/ansible/roles/keycloak/handlers/main.yml
new file mode 100644
index 000000000..589bdabcd
--- /dev/null
+++ b/ansible/roles/keycloak/handlers/main.yml
@@ -0,0 +1,26 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+
+# Gracefully reload httpd
+- name: restart httpd
+  service: name=httpd state=reloaded enabled=yes
+  become: yes
diff --git a/ansible/roles/keycloak/tasks/main.yml b/ansible/roles/keycloak/tasks/main.yml
new file mode 100644
index 000000000..268d6ac0d
--- /dev/null
+++ b/ansible/roles/keycloak/tasks/main.yml
@@ -0,0 +1,217 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: Install Keycloak pre-requisites (Debian)
+  apt: name={{ item }} state=latest update_cache=yes
+  with_items:
+    - maven
+  become: yes
+  when: ansible_os_family == "Debian"
+
+- name: Setup postgresql for keycloak
+  include_tasks: setup_postgres.yml
+
+- name: Restore old server's dump file
+  include_tasks: restore_db.yml
+  tags: [never, migrate_db]
+
+- name: Create Keycloak deployment directory {{ keycloak_install_dir }}
+  file: path={{ keycloak_install_dir }}
+    state=directory
+    mode=0755
+    owner={{ user }}
+    group={{ group }}
+
+- name: Create Keycloak source directory
+  file: path={{ keycloak_source_dir_new }}
+    state=directory
+    mode=0755
+    owner={{ user }}
+    group={{ group }}
+
+- name: get keycloak zip
+  get_url:
+    dest: "{{ user_home }}"
+    url: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_version }}/keycloak-{{ keycloak_version }}.zip"
+  become: yes
+
+- name: ensure unzip present
+  apt:
+    name: unzip
+    update_cache: yes
+  become: yes
+
+- name: place unzipped keycloak on path
+  unarchive:
+    src: "/{{ user_home }}/keycloak-{{ keycloak_version }}.zip"
+    dest: "{{ user_home }}"
+    remote_src: yes
+    owner: "{{ user }}"
+  become: yes
+
+- name: Delete default configuration file
+  file:
+    state: absent
+    path: "{{ keycloak_install_dir }}/conf/keycloak.conf"
+  become: yes
+  ignore_errors: yes
+
+- name: copy configuration file (keycloak.conf)
+  template: >
+    src=keycloak.conf.j2
+    dest="{{ keycloak_install_dir }}/conf/keycloak.conf"
+    owner="{{ user }}"
+    group="{{ group }}"
+    mode="u=rw,g=r,o=r"
+  become: yes
+
+# <--------------------------start keycloak Identity server------------------------------>
+- name: create keycloak daemon process
+  template: >
+    src=keycloak.service.j2
+    dest="/etc/systemd/system/keycloak.service"
+    owner="{{ user }}"
+    group="{{ group }}"
+    mode="u=rwx,g=rx,o=rx"
+  become: yes
+
+- name: reload systemctl daemon
+  command: systemctl daemon-reload
+  become: yes
+  tags:
+    - always
+
+- name: Restart Keycloak server
+  service:
+    name: keycloak
+    state: restarted
+    enabled: yes
+  become: yes
+
+#- name: Run Keycloak maven build
+#  command: mvn -Pdistribution -pl distribution/server-dist -am -Dmaven.test.skip clean install chdir="{{ keycloak_source_dir_new }}/"
+#  environment:
+#    MAVEN_OPTS: "-Xmx2048m"
+#  register: build
+#  tags: update
+#  become_user: "{{ user }}"
+#
+## Unarchive keycloak distribution
+#- name: Unarchive keycloak
+#  unarchive:
+#    src: "{{ keycloak_source_dir_new }}/distribution/server-dist/target/keycloak-{{ keycloak_version }}.zip"
+#    dest: "{{ user_home }}"
+#    copy: no
+#  become_user: "{{ user }}"
+#
+#- name: Create modules/system/layers/keycloak/org/postgresql directory
+#  become: yes
+#  file:
+#    path: "{{ user_home }}/{{ keycloak_install_dir }}/modules/system/layers/keycloak/org/postgresql/main"
+#    state: directory
+#    mode: 0755
+#    owner: "{{ user }}"
+#    group: "{{ group }}"
+#
+#- name: copy module.xml to org/postgresql dir
+#  template:
+#    src: module.xml.j2
+#    dest: "{{ user_home }}/{{ keycloak_install_dir }}/modules/system/layers/keycloak/org/postgresql/main/module.xml"
+#    owner: "{{ user }}"
+#    group: "{{ group }}"
+#    mode: '0644'
+#  become: yes
+#  become_user: "{{ user }}"
+#
+#- name: Download postgresql jar
+#  ansible.builtin.get_url:
+#    url: https://jdbc.postgresql.org/download/postgresql-42.3.6.jar
+#    dest: "{{ keycloak_deployment_dir }}/modules/system/layers/keycloak/org/postgresql/main/postgresql-42.3.6.jar"
+#    mode: '0644'
+#
+#- name: Setup postgresql for keycloak
+#  include_tasks: setup_postgres.yml
+#
+#- name: Restore old server's dump file
+#  include_tasks: restore_db.yml
+#  tags: [never, migrate_db]
+#
+## <---------------------------- Server Configuration -------------------------------->
+#
+## SSL Configuration & postgresql
+#- name: copy keycloak configuration file (Standalone)
+#  template: >
+#    src=standalone.xml.j2
+#    dest="{{ user_home }}/{{ keycloak_install_dir }}/standalone/configuration/standalone.xml"
+#    owner="{{ user }}"
+#    group="{{ group }}"
+#    mode="u=rw,g=r,o=r"
+#  become_user: "{{ user }}"
+#  tags:
+#       - standalone
+#
+## </------------------------------ Server Configuration ends ---------------------------->
+#
+## <---------- setup init script for keycloak, starts the server after reboot ----------->
+#
+#- name: Create Keycloak run directory
+#  become: yes
+#  file:
+#    path: "{{ user_home }}/run"
+#    state: directory
+#    mode: 0755
+#    owner: "{{ user }}"
+#    group: "{{ group }}"
+#
+#- name: Copy keycloak script to run directory
+#  template: >
+#    src=keycloak-standalone-init.j2
+#    dest="{{ user_home }}/run/keycloak.sh"
+#    owner="{{ user }}"
+#    group="{{ group }}"
+#    mode="u=rwx,g=rx,o=rx"
+#  become_user: "{{ user }}"
+#  tags:
+#    - standalone
+#
+#- name: copy systemd script file (Standalone) for {{ user }}
+#  template: >
+#    src=keycloak.service.j2
+#    dest="/etc/systemd/system/keycloak.service"
+#    owner="{{ user }}"
+#    group="{{ group }}"
+#    mode="u=rwx,g=rx,o=rx"
+#  become: yes
+#  tags:
+#    - standalone
+#
+## <--------------------------start keycloak Identity server------------------------------>
+#- name: reload systemctl daemon
+#  command: systemctl daemon-reload
+#  become: yes
+#  tags:
+#    - always
+#
+#- name: Restart Keycloak server
+#  service:
+#    name: keycloak
+#    state: restarted
+#    enabled: yes
+#  become: yes
diff --git a/ansible/roles/keycloak/tasks/old_main.yml b/ansible/roles/keycloak/tasks/old_main.yml
new file mode 100644
index 000000000..f4aa2e8ad
--- /dev/null
+++ b/ansible/roles/keycloak/tasks/old_main.yml
@@ -0,0 +1,243 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: Install Keycloak pre-requisites (Debian)
+  apt: name={{ item }} state=latest update_cache=yes
+  with_items:
+    - maven
+  become: yes
+  when: ansible_os_family == "Debian"
+
+- name: Create Keycloak deployment directory {{ keycloak_install_dir }}
+  file: path={{ keycloak_install_dir }}
+    state=directory
+    mode=0755
+    owner={{ user }}
+    group={{ group }}
+
+- name: Create Keycloak source directory
+  file: path={{ keycloak_source_dir_new }}
+    state=directory
+    mode=0755
+    owner={{ user }}
+    group={{ group }}
+
+# Clone Keycloak repo
+- name: git checkout from Keycloak github repo {{ keycloak_repo }} # branch {{ keycloak_git_branch }}
+  git:
+    repo: "{{ keycloak_repo }}"
+    dest: "{{ keycloak_source_dir_new }}"
+    version: "{{ keycloak_version }}"
+    force: yes
+  register: checkout
+  tags: update
+  become_user: "{{ user }}"
+
+- name: Run Keycloak maven build
+  command: mvn -Pdistribution -pl distribution/server-dist -am -Dmaven.test.skip clean install chdir="{{ keycloak_source_dir_new }}/"
+  environment:
+    MAVEN_OPTS: "-Xmx2048m"
+  register: build
+  tags: update
+  become_user: "{{ user }}"
+
+- name: Delete configuration directories of the distributions
+  file:
+    state: absent
+    path: "{{ keycloak_install_dir }}/standalone/configuration"
+  become_user: "{{ user }}"
+  ignore_errors: yes
+
+# Unarchive keycloak distribution
+- name: Unarchive keycloak
+  unarchive:
+    src: "{{ keycloak_source_dir_new }}/distribution/server-dist/target/keycloak-{{ keycloak_version }}.zip"
+    dest: "{{ user_home }}"
+    copy: no
+  become_user: "{{ user }}"
+
+- name: Create modules/system/layers/keycloak/org/postgresql directory
+  become: yes
+  file:
+    path: "{{ user_home }}/{{ keycloak_install_dir }}/modules/system/layers/keycloak/org/postgresql/main"
+    state: directory
+    mode: 0755
+    owner: "{{ user }}"
+    group: "{{ group }}"
+
+- name: copy module.xml to org/postgresql dir
+  template:
+    src: module.xml.j2
+    dest: "{{ user_home }}/{{ keycloak_install_dir }}/modules/system/layers/keycloak/org/postgresql/main/module.xml"
+    owner: "{{ user }}"
+    group: "{{ group }}"
+    mode: '0644'
+  become: yes
+  become_user: "{{ user }}"
+
+- name: Download postgresql jar
+  ansible.builtin.get_url:
+    url: https://jdbc.postgresql.org/download/postgresql-42.3.6.jar
+    dest: "{{ user_home }}/{{ keycloak_install_dir }}/modules/system/layers/keycloak/org/postgresql/main/postgresql-42.3.6.jar"
+    mode: '0644'
+
+# setup postgresql for keycloak
+- name: Install postgresql and postgresql-contrib
+  apt:
+    name:
+      - postgresql
+      - postgresql-contrib
+  become: yes
+
+- name: "Install Python packages"
+  apt:
+    name: "{{ item }}"
+    state: present
+  with_items:
+    - python3-psycopg2
+  become: yes
+
+- name: Start the postgresql service
+  service:
+    name: postgresql
+    state: started
+    enabled: yes
+  become: yes
+
+- name: "Create database"
+  postgresql_db:
+    state: present
+    name: "{{ keycloak_db_schema_name }}"
+    login_password: "{{ keycloak_db_password }}"
+  become: yes
+  become_user: postgres
+
+- name: "Create db user"
+  postgresql_user:
+    state: present
+    name: "{{ keycloak_db_username }}"
+    password: "{{ keycloak_db_password }}"
+    login_password: "{{ keycloak_db_password }}"
+  become: yes
+  become_user: postgres
+
+- name: "Grant db user access to app db"
+  postgresql_privs:
+    type: database
+    database: "{{ keycloak_db_schema_name }}"
+    roles: "{{ keycloak_db_username }}"
+    grant_option: no
+    privs: all
+    login_password: "{{ keycloak_db_password }}"
+  become: yes
+  become_user: postgres
+
+- name: copy postgres hba conf
+  template:
+    src: pg_hba.conf.j2
+    dest: /etc/postgresql/12/main/pg_hba.conf
+    owner: root
+    group: root
+    mode: '0644'
+  become: yes
+
+- name: Restart the postgresql service
+  service:
+    name: postgresql
+    state: restarted
+  become: yes
+
+- name: Copy dump file from master node to new server
+  copy:
+    src: tmp/postgresDB_arch.sql
+    dest: /home/exouser/backups/
+
+# TODO: It appends dump -> but we need to replace it
+- name: Restore dump
+  postgresql_db:
+    state: restore
+    name: "{{ keycloak_db_schema_name }}"
+    target: /home/exouser/backups/postgresDB_arch.sql
+    login_password: "{{ keycloak_db_password }}"
+  become: yes
+  become_user: postgres
+
+# <---------------------------- Server Configuration -------------------------------->
+
+# SSL Configuration & postgresql
+- name: copy keycloak configuration file (Standalone)
+  template: >
+    src=standalone.xml.j2
+    dest="{{ user_home }}/{{ keycloak_install_dir }}/standalone/configuration/standalone.xml"
+    owner="{{ user }}"
+    group="{{ group }}"
+    mode="u=rw,g=r,o=r"
+  become_user: "{{ user }}"
+  tags:
+       - standalone
+
+# </------------------------------ Server Configuration ends ---------------------------->
+
+# <---------- setup init script for keycloak, starts the server after reboot ----------->
+
+- name: Create Keycloak run directory
+  become: yes
+  file:
+    path: "{{ user_home }}/run"
+    state: directory
+    mode: 0755
+    owner: "{{ user }}"
+    group: "{{ group }}"
+
+- name: Copy keycloak script to run directory
+  template: >
+    src=keycloak-standalone-init.j2
+    dest="{{ user_home }}/run/keycloak.sh"
+    owner="{{ user }}"
+    group="{{ group }}"
+    mode="u=rwx,g=rx,o=rx"
+  become_user: "{{ user }}"
+  tags:
+    - standalone
+
+- name: copy systemd script file (Standalone) for {{ user }}
+  template: >
+    src=keycloak.service.j2
+    dest="/etc/systemd/system/keycloak.service"
+    owner="{{ user }}"
+    group="{{ group }}"
+    mode="u=rwx,g=rx,o=rx"
+  become: yes
+  tags:
+    - standalone
+
+# <--------------------------start keycloak Identity server------------------------------>
+- name: reload systemctl daemon
+  command: systemctl daemon-reload
+  become: yes
+  tags:
+       - always
+
+- name: start Keycloak server
+  service:
+    name: keycloak
+    state: restarted
+    enabled: yes
+  become: yes
diff --git a/ansible/roles/keycloak/tasks/restore_db.yml b/ansible/roles/keycloak/tasks/restore_db.yml
new file mode 100644
index 000000000..bb5a55370
--- /dev/null
+++ b/ansible/roles/keycloak/tasks/restore_db.yml
@@ -0,0 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: Copy dump file from master node to new server
+  copy:
+    src: tmp/postgresDB_arch.sql
+    dest: /home/exouser/backups/
+
+# TODO: It appends dump -> but we need to replace it
+- name: Restore dump
+  postgresql_db:
+    state: restore
+    name: "{{ keycloak_db_schema_name }}"
+    target: /home/exouser/backups/postgresDB_arch.sql
+    login_password: "{{ keycloak_db_password }}"
+  become: yes
+  become_user: postgres
\ No newline at end of file
diff --git a/ansible/roles/keycloak/tasks/setup_postgres.yml b/ansible/roles/keycloak/tasks/setup_postgres.yml
new file mode 100644
index 000000000..94f4bcc0c
--- /dev/null
+++ b/ansible/roles/keycloak/tasks/setup_postgres.yml
@@ -0,0 +1,84 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: Install postgresql and postgresql-contrib
+  apt:
+    name:
+      - postgresql
+      - postgresql-contrib
+  become: yes
+
+- name: "Install Python packages"
+  apt:
+    name: "{{ item }}"
+    state: present
+  with_items:
+    - python3-psycopg2
+  become: yes
+
+- name: Start the postgresql service
+  service:
+    name: postgresql
+    state: started
+    enabled: yes
+  become: yes
+
+- name: "Create database"
+  postgresql_db:
+    state: present
+    name: "{{ keycloak_db_schema_name }}"
+    login_password: "{{ keycloak_db_password }}"
+  become: yes
+  become_user: postgres
+
+- name: "Create db user"
+  postgresql_user:
+    state: present
+    name: "{{ keycloak_db_username }}"
+    password: "{{ keycloak_db_password }}"
+    login_password: "{{ keycloak_db_password }}"
+  become: yes
+  become_user: postgres
+
+- name: "Grant db user access to app db"
+  postgresql_privs:
+    type: database
+    database: "{{ keycloak_db_schema_name }}"
+    roles: "{{ keycloak_db_username }}"
+    grant_option: no
+    privs: all
+    login_password: "{{ keycloak_db_password }}"
+  become: yes
+  become_user: postgres
+
+- name: copy postgres hba conf
+  template:
+    src: pg_hba.conf.j2
+    dest: /etc/postgresql/12/main/pg_hba.conf
+    owner: root
+    group: root
+    mode: '0644'
+  become: yes
+
+- name: Restart the postgresql service
+  service:
+    name: postgresql
+    state: restarted
+  become: yes
\ No newline at end of file
diff --git a/ansible/roles/keycloak/templates/basic-vhost.conf.j2 b/ansible/roles/keycloak/templates/basic-vhost.conf.j2
new file mode 100644
index 000000000..da78c4ce2
--- /dev/null
+++ b/ansible/roles/keycloak/templates/basic-vhost.conf.j2
@@ -0,0 +1,9 @@
+<VirtualHost *:80>
+    ServerName {{ groups['keycloak'][0] }}
+    DocumentRoot "/var/www/html"
+
+    <Directory /var/www/html>
+        Options -Indexes +FollowSymLinks
+        AllowOverride All
+    </Directory>
+</VirtualHost>
diff --git a/ansible/roles/keycloak/templates/keycloak-standalone-init.j2 b/ansible/roles/keycloak/templates/keycloak-standalone-init.j2
new file mode 100644
index 000000000..6a3943010
--- /dev/null
+++ b/ansible/roles/keycloak/templates/keycloak-standalone-init.j2
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# chkconfig: 35 90 12
+# description: keycloak server
+#
+
+# Get function from functions library
+. /lib/lsb/init-functions
+#. /etc/init.d/functions
+
+# Start the service Keycloak
+start() {
+        {{ user_home }}/{{ keycloak_install_dir }}/bin/standalone.sh
+        ### Create the lock file ###
+        #touch /v/keycloak
+        echo $"keycloak server running"
+}
+
+# Restart the service FOO
+stop() {
+        ps aux | grep keycloak | grep -v grep | awk '{print $2}' | xargs kill
+        ### Now, delete the lock file ###
+        #rm -f /var/lock/subsys/keycloak
+        echo $"keycloak server stopped"
+}
+
+### main logic ###
+case "$1" in
+  start)
+        start
+        ;;
+  stop)
+        stop
+        ;;
+  status)
+        status keycloak
+        ;;
+  restart|reload|condrestart)
+        stop
+        start
+        ;;
+  *)
+        echo $"Usage: $0 {start|stop|restart|reload|status}"
+        exit 1
+esac
\ No newline at end of file
diff --git a/ansible/roles/keycloak/templates/keycloak.conf.j2 b/ansible/roles/keycloak/templates/keycloak.conf.j2
new file mode 100644
index 000000000..ffd309422
--- /dev/null
+++ b/ansible/roles/keycloak/templates/keycloak.conf.j2
@@ -0,0 +1,43 @@
+# Basic settings for running in production. Change accordingly before deploying the server.
+
+# Database
+
+# The database vendor.
+db=postgres
+
+# The username of the database user.
+db-username={{keycloak_db_username}}
+
+# The password of the database user.
+db-password={{keycloak_db_password}}
+
+# The full database JDBC URL. If not provided, a default URL is set based on the selected database vendor.
+db-url={{keycloak_db_url}}
+
+# Observability
+
+# If the server should expose healthcheck endpoints.
+#health-enabled=true
+
+# If the server should expose metrics endpoints.
+#metrics-enabled=true
+
+# HTTP
+
+# The file path to a server certificate or certificate chain in PEM format.
+https-certificate-file=/{{ user_home }}/certs/fullchain.pem
+
+# The file path to a private key in PEM format.
+https-certificate-key-file=/{{ user_home }}/certs/privkey.pem
+
+# To make it compatible with the older version where keycloak is accessed at /auth
+http-relative-path=/auth
+
+# The proxy address forwarding mode if the server is behind a reverse proxy.
+proxy=edge
+
+# Do not attach route to cookies and rely on the session affinity capabilities from reverse proxy
+#spi-sticky-session-encoder-infinispan-should-attach-route=false
+
+# Hostname for the Keycloak server.
+hostname={{ ansible_host }}
diff --git a/ansible/roles/keycloak/templates/keycloak.service.j2 b/ansible/roles/keycloak/templates/keycloak.service.j2
new file mode 100644
index 000000000..9abdbdc5b
--- /dev/null
+++ b/ansible/roles/keycloak/templates/keycloak.service.j2
@@ -0,0 +1,14 @@
+[Unit]
+Description=Keycloak service
+After=network.target
+
+[Service]
+User={{ user }}
+Group={{ group }}
+ExecStart={{ user_home }}/{{ keycloak_install_dir }}/bin/kc.sh start
+Restart=always
+TimeoutSec=60
+Type=Forking
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/ansible/roles/keycloak/templates/module.j2 b/ansible/roles/keycloak/templates/module.j2
new file mode 100644
index 000000000..45da6243a
--- /dev/null
+++ b/ansible/roles/keycloak/templates/module.j2
@@ -0,0 +1,12 @@
+<?xml version="1.0" ?>
+<module xmlns="urn:jboss:module:1.3" name="org.mysql">
+
+    <resources>
+        <resource-root path="{{keycloak_db_connector_name}}-bin.jar"/>
+    </resources>
+
+    <dependencies>
+        <module name="javax.api"/>
+        <module name="javax.transaction.api"/>
+    </dependencies>
+</module>
\ No newline at end of file
diff --git a/ansible/roles/keycloak/templates/module.xml.j2 b/ansible/roles/keycloak/templates/module.xml.j2
new file mode 100644
index 000000000..8eed0982a
--- /dev/null
+++ b/ansible/roles/keycloak/templates/module.xml.j2
@@ -0,0 +1,12 @@
+<?xml version="1.0" ?>
+<module xmlns="urn:jboss:module:1.3" name="org.postgresql">
+
+    <resources>
+        <resource-root path="postgresql-42.3.6.jar"/>
+    </resources>
+
+    <dependencies>
+        <module name="javax.api"/>
+        <module name="javax.transaction.api"/>
+    </dependencies>
+</module>
\ No newline at end of file
diff --git a/ansible/roles/keycloak/templates/pg_hba.conf.j2 b/ansible/roles/keycloak/templates/pg_hba.conf.j2
new file mode 100644
index 000000000..02d32e5c6
--- /dev/null
+++ b/ansible/roles/keycloak/templates/pg_hba.conf.j2
@@ -0,0 +1,103 @@
+# PostgreSQL Client Authentication Configuration File
+# ===================================================
+#
+# Refer to the "Client Authentication" section in the PostgreSQL
+# documentation for a complete description of this file.  A short
+# synopsis follows.
+#
+# This file controls: which hosts are allowed to connect, how clients
+# are authenticated, which PostgreSQL user names they can use, which
+# databases they can access.  Records take one of these forms:
+#
+# local         DATABASE  USER  METHOD  [OPTIONS]
+# host          DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+# hostssl       DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+# hostnossl     DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+# hostgssenc    DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+# hostnogssenc  DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+#
+# (The uppercase items must be replaced by actual values.)
+#
+# The first field is the connection type: "local" is a Unix-domain
+# socket, "host" is either a plain or SSL-encrypted TCP/IP socket,
+# "hostssl" is an SSL-encrypted TCP/IP socket, and "hostnossl" is a
+# non-SSL TCP/IP socket.  Similarly, "hostgssenc" uses a
+# GSSAPI-encrypted TCP/IP socket, while "hostnogssenc" uses a
+# non-GSSAPI socket.
+#
+# DATABASE can be "all", "sameuser", "samerole", "replication", a
+# database name, or a comma-separated list thereof. The "all"
+# keyword does not match "replication". Access to replication
+# must be enabled in a separate record (see example below).
+#
+# USER can be "all", a user name, a group name prefixed with "+", or a
+# comma-separated list thereof.  In both the DATABASE and USER fields
+# you can also write a file name prefixed with "@" to include names
+# from a separate file.
+#
+# ADDRESS specifies the set of hosts the record matches.  It can be a
+# host name, or it is made up of an IP address and a CIDR mask that is
+# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that
+# specifies the number of significant bits in the mask.  A host name
+# that starts with a dot (.) matches a suffix of the actual host name.
+# Alternatively, you can write an IP address and netmask in separate
+# columns to specify the set of hosts.  Instead of a CIDR-address, you
+# can write "samehost" to match any of the server's own IP addresses,
+# or "samenet" to match any address in any subnet that the server is
+# directly connected to.
+#
+# METHOD can be "trust", "reject", "md5", "password", "scram-sha-256",
+# "gss", "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert".
+# Note that "password" sends passwords in clear text; "md5" or
+# "scram-sha-256" are preferred since they send encrypted passwords.
+#
+# OPTIONS are a set of options for the authentication in the format
+# NAME=VALUE.  The available options depend on the different
+# authentication methods -- refer to the "Client Authentication"
+# section in the documentation for a list of which options are
+# available for which authentication methods.
+#
+# Database and user names containing spaces, commas, quotes and other
+# special characters must be quoted.  Quoting one of the keywords
+# "all", "sameuser", "samerole" or "replication" makes the name lose
+# its special character, and just match a database or username with
+# that name.
+#
+# This file is read on server startup and when the server receives a
+# SIGHUP signal.  If you edit the file on a running system, you have to
+# SIGHUP the server for the changes to take effect, run "pg_ctl reload",
+# or execute "SELECT pg_reload_conf()".
+#
+# Put your actual configuration here
+# ----------------------------------
+#
+# If you want to allow non-local connections, you need to add more
+# "host" records.  In that case you will also need to make PostgreSQL
+# listen on a non-local interface via the listen_addresses
+# configuration parameter, or via the -i or -h command line switches.
+
+
+
+
+# DO NOT DISABLE!
+# If you change this first entry you will need to make sure that the
+# database superuser can access the database using some other method.
+# Noninteractive access to all databases is required during automatic
+# maintenance (custom daily cronjobs, replication, and similar tasks).
+#
+# Database administrative login by Unix domain socket
+local   all             postgres                                md5
+
+# TYPE  DATABASE        USER            ADDRESS                 METHOD
+
+# "local" is for Unix domain socket connections only
+local   all             all                                     peer
+# IPv4 local connections:
+host    all             all             127.0.0.1/32            md5
+# IPv6 local connections:
+host    all             all             ::1/128                 md5
+# Allow replication connections from localhost, by a user with the
+# replication privilege.
+local   replication     all                                     peer
+host    replication     all             127.0.0.1/32            md5
+host    replication     all             ::1/128                 md5
\ No newline at end of file
diff --git a/ansible/roles/keycloak/templates/standalone.xml.j2 b/ansible/roles/keycloak/templates/standalone.xml.j2
new file mode 100644
index 000000000..65487a4e7
--- /dev/null
+++ b/ansible/roles/keycloak/templates/standalone.xml.j2
@@ -0,0 +1,645 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<server xmlns="urn:jboss:domain:10.0">
+    <extensions>
+        <extension module="org.jboss.as.clustering.infinispan"/>
+        <extension module="org.jboss.as.connector"/>
+        <extension module="org.jboss.as.deployment-scanner"/>
+        <extension module="org.jboss.as.ee"/>
+        <extension module="org.jboss.as.ejb3"/>
+        <extension module="org.jboss.as.jaxrs"/>
+        <extension module="org.jboss.as.jmx"/>
+        <extension module="org.jboss.as.jpa"/>
+        <extension module="org.jboss.as.logging"/>
+        <extension module="org.jboss.as.mail"/>
+        <extension module="org.jboss.as.naming"/>
+        <extension module="org.jboss.as.remoting"/>
+        <extension module="org.jboss.as.security"/>
+        <extension module="org.jboss.as.transactions"/>
+        <extension module="org.jboss.as.weld"/>
+        <extension module="org.keycloak.keycloak-server-subsystem"/>
+        <extension module="org.wildfly.extension.bean-validation"/>
+        <extension module="org.wildfly.extension.core-management"/>
+        <extension module="org.wildfly.extension.elytron"/>
+        <extension module="org.wildfly.extension.io"/>
+        <extension module="org.wildfly.extension.microprofile.config-smallrye"/>
+        <extension module="org.wildfly.extension.microprofile.health-smallrye"/>
+        <extension module="org.wildfly.extension.microprofile.metrics-smallrye"/>
+        <extension module="org.wildfly.extension.request-controller"/>
+        <extension module="org.wildfly.extension.security.manager"/>
+        <extension module="org.wildfly.extension.undertow"/>
+    </extensions>
+    <management>
+        <security-realms>
+            <security-realm name="ManagementRealm">
+                <authentication>
+                    <local default-user="$local" skip-group-loading="true"/>
+                    <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
+                </authentication>
+                <authorization map-groups-to-roles="false">
+                    <properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
+                </authorization>
+            </security-realm>
+            <security-realm name="ApplicationRealm">
+                <server-identities>
+                    <ssl>
+                        <keystore path="application.keystore" relative-to="jboss.server.config.dir"
+                                  keystore-password="password" alias="server" key-password="password"
+                                  generate-self-signed-certificate-host="localhost"/>
+                    </ssl>
+                </server-identities>
+                <authentication>
+                    <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
+                    <properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
+                </authentication>
+                <authorization>
+                    <properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
+                </authorization>
+            </security-realm>
+        </security-realms>
+        <audit-log>
+            <formatters>
+                <json-formatter name="json-formatter"/>
+            </formatters>
+            <handlers>
+                <file-handler name="file" formatter="json-formatter" path="audit-log.log"
+                              relative-to="jboss.server.data.dir"/>
+            </handlers>
+            <logger log-boot="true" log-read-only="false" enabled="false">
+                <handlers>
+                    <handler name="file"/>
+                </handlers>
+            </logger>
+        </audit-log>
+        <management-interfaces>
+            <http-interface security-realm="ManagementRealm">
+                <http-upgrade enabled="true"/>
+                <socket-binding http="management-http"/>
+            </http-interface>
+        </management-interfaces>
+        <access-control provider="simple">
+            <role-mapping>
+                <role name="SuperUser">
+                    <include>
+                        <user name="$local"/>
+                    </include>
+                </role>
+            </role-mapping>
+        </access-control>
+    </management>
+    <profile>
+        <subsystem xmlns="urn:jboss:domain:logging:8.0">
+            <console-handler name="CONSOLE">
+                <level name="INFO"/>
+                <formatter>
+                    <named-formatter name="COLOR-PATTERN"/>
+                </formatter>
+            </console-handler>
+            <periodic-rotating-file-handler name="FILE" autoflush="true">
+                <formatter>
+                    <named-formatter name="PATTERN"/>
+                </formatter>
+                <file relative-to="jboss.server.log.dir" path="server.log"/>
+                <suffix value=".yyyy-MM-dd"/>
+                <append value="true"/>
+            </periodic-rotating-file-handler>
+            <logger category="com.arjuna">
+                <level name="WARN"/>
+            </logger>
+            <logger category="io.jaegertracing.Configuration">
+                <level name="WARN"/>
+            </logger>
+            <logger category="org.jboss.as.config">
+                <level name="DEBUG"/>
+            </logger>
+            <logger category="sun.rmi">
+                <level name="WARN"/>
+            </logger>
+            <root-logger>
+                <level name="INFO"/>
+                <handlers>
+                    <handler name="CONSOLE"/>
+                    <handler name="FILE"/>
+                </handlers>
+            </root-logger>
+            <formatter name="PATTERN">
+                <pattern-formatter pattern="%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
+            </formatter>
+            <formatter name="COLOR-PATTERN">
+                <pattern-formatter pattern="%K{level}%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n"/>
+            </formatter>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:bean-validation:1.0"/>
+        <subsystem xmlns="urn:jboss:domain:core-management:1.0"/>
+        <subsystem xmlns="urn:jboss:domain:datasources:5.0">
+            <datasources>
+                <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true"
+                            use-java-context="true"
+                            statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
+                    <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
+                    <driver>h2</driver>
+                    <security>
+                        <user-name>sa</user-name>
+                        <password>sa</password>
+                    </security>
+                </datasource>
+                <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true"
+                            use-java-context="true">
+                    <connection-url>{{keycloak_db_url}}</connection-url>
+                    <driver>postgresql</driver>
+                    <pool>
+                        <max-pool-size>{{keycloak_db_pool_size}}</max-pool-size>
+                    </pool>
+                    <security>
+                        <user-name>{{keycloak_db_username}}</user-name>
+                        <password>{{keycloak_db_password}}</password>
+                    </security>
+                </datasource>
+                <drivers>
+                    <driver name="postgresql" module="org.postgresql">
+                        <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
+                    </driver>
+                    <driver name="h2" module="com.h2database.h2">
+                        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
+                    </driver>
+                </drivers>
+            </datasources>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
+            <deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000"
+                                runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:ee:4.0">
+            <spec-descriptor-property-replacement>false</spec-descriptor-property-replacement>
+            <concurrent>
+                <context-services>
+                    <context-service name="default" jndi-name="java:jboss/ee/concurrency/context/default"
+                                     use-transaction-setup-provider="true"/>
+                </context-services>
+                <managed-thread-factories>
+                    <managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default"
+                                            context-service="default"/>
+                </managed-thread-factories>
+                <managed-executor-services>
+                    <managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default"
+                                              context-service="default" hung-task-threshold="60000"
+                                              keepalive-time="5000"/>
+                </managed-executor-services>
+                <managed-scheduled-executor-services>
+                    <managed-scheduled-executor-service name="default"
+                                                        jndi-name="java:jboss/ee/concurrency/scheduler/default"
+                                                        context-service="default" hung-task-threshold="60000"
+                                                        keepalive-time="3000"/>
+                </managed-scheduled-executor-services>
+            </concurrent>
+            <default-bindings context-service="java:jboss/ee/concurrency/context/default"
+                              datasource="java:jboss/datasources/ExampleDS"
+                              managed-executor-service="java:jboss/ee/concurrency/executor/default"
+                              managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default"
+                              managed-thread-factory="java:jboss/ee/concurrency/factory/default"/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:ejb3:6.0">
+            <session-bean>
+                <stateless>
+                    <bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
+                </stateless>
+                <stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
+                <singleton default-access-timeout="5000"/>
+            </session-bean>
+            <pools>
+                <bean-instance-pools>
+                    <strict-max-pool name="mdb-strict-max-pool" derive-size="from-cpu-count"
+                                     instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
+                    <strict-max-pool name="slsb-strict-max-pool" derive-size="from-worker-pools"
+                                     instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
+                </bean-instance-pools>
+            </pools>
+            <caches>
+                <cache name="simple"/>
+                <cache name="distributable" passivation-store-ref="infinispan" aliases="passivating clustered"/>
+            </caches>
+            <passivation-stores>
+                <passivation-store name="infinispan" cache-container="ejb" max-size="10000"/>
+            </passivation-stores>
+            <async thread-pool-name="default"/>
+            <timer-service thread-pool-name="default" default-data-store="default-file-store">
+                <data-stores>
+                    <file-data-store name="default-file-store" path="timer-service-data"
+                                     relative-to="jboss.server.data.dir"/>
+                </data-stores>
+            </timer-service>
+            <remote connector-ref="http-remoting-connector" thread-pool-name="default">
+                <channel-creation-options>
+                    <option name="MAX_OUTBOUND_MESSAGES" value="1234" type="remoting"/>
+                </channel-creation-options>
+            </remote>
+            <thread-pools>
+                <thread-pool name="default">
+                    <max-threads count="10"/>
+                    <keepalive-time time="60" unit="seconds"/>
+                </thread-pool>
+            </thread-pools>
+            <default-security-domain value="other"/>
+            <default-missing-method-permissions-deny-access value="true"/>
+            <statistics enabled="${wildfly.ejb3.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
+            <log-system-exceptions value="true"/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:io:3.0">
+            <worker name="default"/>
+            <buffer-pool name="default"/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:infinispan:9.0">
+            <cache-container name="keycloak">
+                <local-cache name="realms">
+                    <object-memory size="10000"/>
+                </local-cache>
+                <local-cache name="users">
+                    <object-memory size="10000"/>
+                </local-cache>
+                <local-cache name="sessions"/>
+                <local-cache name="authenticationSessions"/>
+                <local-cache name="offlineSessions"/>
+                <local-cache name="clientSessions"/>
+                <local-cache name="offlineClientSessions"/>
+                <local-cache name="loginFailures"/>
+                <local-cache name="work"/>
+                <local-cache name="authorization">
+                    <object-memory size="10000"/>
+                </local-cache>
+                <local-cache name="keys">
+                    <object-memory size="1000"/>
+                    <expiration max-idle="3600000"/>
+                </local-cache>
+                <local-cache name="actionTokens">
+                    <object-memory size="-1"/>
+                    <expiration max-idle="-1" interval="300000"/>
+                </local-cache>
+            </cache-container>
+            <cache-container name="server" default-cache="default" module="org.wildfly.clustering.server">
+                <local-cache name="default">
+                    <transaction mode="BATCH"/>
+                </local-cache>
+            </cache-container>
+            <cache-container name="web" default-cache="passivation" module="org.wildfly.clustering.web.infinispan">
+                <local-cache name="passivation">
+                    <locking isolation="REPEATABLE_READ"/>
+                    <transaction mode="BATCH"/>
+                    <file-store passivation="true" purge="false"/>
+                </local-cache>
+                <local-cache name="sso">
+                    <locking isolation="REPEATABLE_READ"/>
+                    <transaction mode="BATCH"/>
+                </local-cache>
+                <local-cache name="routing"/>
+            </cache-container>
+            <cache-container name="ejb" aliases="sfsb" default-cache="passivation"
+                             module="org.wildfly.clustering.ejb.infinispan">
+                <local-cache name="passivation">
+                    <locking isolation="REPEATABLE_READ"/>
+                    <transaction mode="BATCH"/>
+                    <file-store passivation="true" purge="false"/>
+                </local-cache>
+            </cache-container>
+            <cache-container name="hibernate" module="org.infinispan.hibernate-cache">
+                <local-cache name="entity">
+                    <object-memory size="10000"/>
+                    <expiration max-idle="100000"/>
+                </local-cache>
+                <local-cache name="local-query">
+                    <object-memory size="10000"/>
+                    <expiration max-idle="100000"/>
+                </local-cache>
+                <local-cache name="timestamps"/>
+            </cache-container>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:jaxrs:1.0"/>
+        <subsystem xmlns="urn:jboss:domain:jca:5.0">
+            <archive-validation enabled="true" fail-on-error="true" fail-on-warn="false"/>
+            <bean-validation enabled="true"/>
+            <default-workmanager>
+                <short-running-threads>
+                    <core-threads count="50"/>
+                    <queue-length count="50"/>
+                    <max-threads count="50"/>
+                    <keepalive-time time="10" unit="seconds"/>
+                </short-running-threads>
+                <long-running-threads>
+                    <core-threads count="50"/>
+                    <queue-length count="50"/>
+                    <max-threads count="50"/>
+                    <keepalive-time time="10" unit="seconds"/>
+                </long-running-threads>
+            </default-workmanager>
+            <cached-connection-manager/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:jmx:1.3">
+            <expose-resolved-model/>
+            <expose-expression-model/>
+            <remoting-connector/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:jpa:1.1">
+            <jpa default-datasource="" default-extended-persistence-inheritance="DEEP"/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:mail:3.0">
+            <mail-session name="default" jndi-name="java:jboss/mail/Default">
+                <smtp-server outbound-socket-binding-ref="mail-smtp"/>
+            </mail-session>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:naming:2.0">
+            <remote-naming/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:remoting:4.0">
+            <http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:request-controller:1.0"/>
+        <subsystem xmlns="urn:jboss:domain:security-manager:1.0">
+            <deployment-permissions>
+                <maximum-set>
+                    <permission class="java.security.AllPermission"/>
+                </maximum-set>
+            </deployment-permissions>
+        </subsystem>
+        <subsystem xmlns="urn:wildfly:elytron:8.0" final-providers="combined-providers"
+                   disallowed-providers="OracleUcrypto">
+            <providers>
+                <aggregate-providers name="combined-providers">
+                    <providers name="elytron"/>
+                    <providers name="openssl"/>
+                </aggregate-providers>
+                <provider-loader name="elytron" module="org.wildfly.security.elytron"/>
+                <provider-loader name="openssl" module="org.wildfly.openssl"/>
+            </providers>
+            <audit-logging>
+                <file-audit-log name="local-audit" path="audit.log" relative-to="jboss.server.log.dir" format="JSON"/>
+            </audit-logging>
+            <security-domains>
+                <security-domain name="ApplicationDomain" default-realm="ApplicationRealm"
+                                 permission-mapper="default-permission-mapper">
+                    <realm name="ApplicationRealm" role-decoder="groups-to-roles"/>
+                    <realm name="local"/>
+                </security-domain>
+                <security-domain name="ManagementDomain" default-realm="ManagementRealm"
+                                 permission-mapper="default-permission-mapper">
+                    <realm name="ManagementRealm" role-decoder="groups-to-roles"/>
+                    <realm name="local" role-mapper="super-user-mapper"/>
+                </security-domain>
+            </security-domains>
+            <security-realms>
+                <identity-realm name="local" identity="$local"/>
+                <properties-realm name="ApplicationRealm">
+                    <users-properties path="application-users.properties" relative-to="jboss.server.config.dir"
+                                      digest-realm-name="ApplicationRealm"/>
+                    <groups-properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
+                </properties-realm>
+                <properties-realm name="ManagementRealm">
+                    <users-properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"
+                                      digest-realm-name="ManagementRealm"/>
+                    <groups-properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
+                </properties-realm>
+            </security-realms>
+            <mappers>
+                <simple-permission-mapper name="default-permission-mapper" mapping-mode="first">
+                    <permission-mapping>
+                        <principal name="anonymous"/>
+                        <permission-set name="default-permissions"/>
+                    </permission-mapping>
+                    <permission-mapping match-all="true">
+                        <permission-set name="login-permission"/>
+                        <permission-set name="default-permissions"/>
+                    </permission-mapping>
+                </simple-permission-mapper>
+                <constant-realm-mapper name="local" realm-name="local"/>
+                <simple-role-decoder name="groups-to-roles" attribute="groups"/>
+                <constant-role-mapper name="super-user-mapper">
+                    <role name="SuperUser"/>
+                </constant-role-mapper>
+            </mappers>
+            <permission-sets>
+                <permission-set name="login-permission">
+                    <permission class-name="org.wildfly.security.auth.permission.LoginPermission"/>
+                </permission-set>
+                <permission-set name="default-permissions">
+                    <permission class-name="org.wildfly.extension.batch.jberet.deployment.BatchPermission"
+                                module="org.wildfly.extension.batch.jberet" target-name="*"/>
+                    <permission class-name="org.wildfly.transaction.client.RemoteTransactionPermission"
+                                module="org.wildfly.transaction.client"/>
+                    <permission class-name="org.jboss.ejb.client.RemoteEJBPermission" module="org.jboss.ejb-client"/>
+                </permission-set>
+            </permission-sets>
+            <http>
+                <http-authentication-factory name="management-http-authentication" security-domain="ManagementDomain"
+                                             http-server-mechanism-factory="global">
+                    <mechanism-configuration>
+                        <mechanism mechanism-name="DIGEST">
+                            <mechanism-realm realm-name="ManagementRealm"/>
+                        </mechanism>
+                    </mechanism-configuration>
+                </http-authentication-factory>
+                <provider-http-server-mechanism-factory name="global"/>
+            </http>
+            <sasl>
+                <sasl-authentication-factory name="application-sasl-authentication" sasl-server-factory="configured"
+                                             security-domain="ApplicationDomain">
+                    <mechanism-configuration>
+                        <mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
+                        <mechanism mechanism-name="DIGEST-MD5">
+                            <mechanism-realm realm-name="ApplicationRealm"/>
+                        </mechanism>
+                    </mechanism-configuration>
+                </sasl-authentication-factory>
+                <sasl-authentication-factory name="management-sasl-authentication" sasl-server-factory="configured"
+                                             security-domain="ManagementDomain">
+                    <mechanism-configuration>
+                        <mechanism mechanism-name="JBOSS-LOCAL-USER" realm-mapper="local"/>
+                        <mechanism mechanism-name="DIGEST-MD5">
+                            <mechanism-realm realm-name="ManagementRealm"/>
+                        </mechanism>
+                    </mechanism-configuration>
+                </sasl-authentication-factory>
+                <configurable-sasl-server-factory name="configured" sasl-server-factory="elytron">
+                    <properties>
+                        <property name="wildfly.sasl.local-user.default-user" value="$local"/>
+                    </properties>
+                </configurable-sasl-server-factory>
+                <mechanism-provider-filtering-sasl-server-factory name="elytron" sasl-server-factory="global">
+                    <filters>
+                        <filter provider-name="WildFlyElytron"/>
+                    </filters>
+                </mechanism-provider-filtering-sasl-server-factory>
+                <provider-sasl-server-factory name="global"/>
+            </sasl>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:security:2.0">
+            <security-domains>
+                <security-domain name="other" cache-type="default">
+                    <authentication>
+                        <login-module code="Remoting" flag="optional">
+                            <module-option name="password-stacking" value="useFirstPass"/>
+                        </login-module>
+                        <login-module code="RealmDirect" flag="required">
+                            <module-option name="password-stacking" value="useFirstPass"/>
+                        </login-module>
+                    </authentication>
+                </security-domain>
+                <security-domain name="jboss-web-policy" cache-type="default">
+                    <authorization>
+                        <policy-module code="Delegating" flag="required"/>
+                    </authorization>
+                </security-domain>
+                <security-domain name="jaspitest" cache-type="default">
+                    <authentication-jaspi>
+                        <login-module-stack name="dummy">
+                            <login-module code="Dummy" flag="optional"/>
+                        </login-module-stack>
+                        <auth-module code="Dummy"/>
+                    </authentication-jaspi>
+                </security-domain>
+                <security-domain name="jboss-ejb-policy" cache-type="default">
+                    <authorization>
+                        <policy-module code="Delegating" flag="required"/>
+                    </authorization>
+                </security-domain>
+            </security-domains>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:transactions:5.0">
+            <core-environment node-identifier="${jboss.tx.node.id:1}">
+                <process-id>
+                    <uuid/>
+                </process-id>
+            </core-environment>
+            <recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
+            <coordinator-environment
+                    statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
+            <object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:weld:4.0"/>
+        <subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0"/>
+        <subsystem xmlns="urn:wildfly:microprofile-health-smallrye:2.0" security-enabled="false"
+                   empty-liveness-checks-status="${env.MP_HEALTH_EMPTY_LIVENESS_CHECKS_STATUS:UP}"
+                   empty-readiness-checks-status="${env.MP_HEALTH_EMPTY_READINESS_CHECKS_STATUS:UP}"/>
+        <subsystem xmlns="urn:wildfly:microprofile-metrics-smallrye:2.0" security-enabled="false" exposed-subsystems="*"
+                   prefix="${wildfly.metrics.prefix:wildfly}"/>
+        <subsystem xmlns="urn:jboss:domain:undertow:10.0" default-server="default-server"
+                   default-virtual-host="default-host" default-servlet-container="default"
+                   default-security-domain="other"
+                   statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
+            <buffer-cache name="default"/>
+            <server name="default-server">
+                <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"
+                               proxy-address-forwarding="true"/>
+                <https-listener name="https" socket-binding="https" security-realm="ApplicationRealm"
+                                enable-http2="true"/>
+                <host name="default-host" alias="localhost">
+                    <location name="/" handler="welcome-content"/>
+                    <http-invoker security-realm="ApplicationRealm"/>
+                </host>
+            </server>
+            <servlet-container name="default">
+                <jsp-config/>
+                <websockets/>
+            </servlet-container>
+            <handlers>
+                <file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
+            </handlers>
+        </subsystem>
+        <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
+            <web-context>auth</web-context>
+            <providers>
+                <provider>classpath:${jboss.home.dir}/providers/*</provider>
+            </providers>
+            <master-realm-name>master</master-realm-name>
+            <scheduled-task-interval>900</scheduled-task-interval>
+            <theme>
+                <staticMaxAge>2592000</staticMaxAge>
+                <cacheThemes>true</cacheThemes>
+                <cacheTemplates>true</cacheTemplates>
+                <dir>${jboss.home.dir}/themes</dir>
+            </theme>
+            <spi name="eventsStore">
+                <provider name="jpa" enabled="true">
+                    <properties>
+                        <property name="exclude-events" value="[&quot;REFRESH_TOKEN&quot;]"/>
+                    </properties>
+                </provider>
+            </spi>
+            <spi name="userCache">
+                <provider name="default" enabled="true"/>
+            </spi>
+            <spi name="userSessionPersister">
+                <default-provider>jpa</default-provider>
+            </spi>
+            <spi name="timer">
+                <default-provider>basic</default-provider>
+            </spi>
+            <spi name="connectionsHttpClient">
+                <provider name="default" enabled="true"/>
+            </spi>
+            <spi name="connectionsJpa">
+                <provider name="default" enabled="true">
+                    <properties>
+                        <property name="dataSource" value="java:jboss/datasources/KeycloakDS"/>
+                        <property name="initializeEmpty" value="true"/>
+                        <property name="migrationStrategy" value="update"/>
+                        <property name="migrationExport" value="${jboss.home.dir}/keycloak-database-update.sql"/>
+                    </properties>
+                </provider>
+            </spi>
+            <spi name="realmCache">
+                <provider name="default" enabled="true"/>
+            </spi>
+            <spi name="connectionsInfinispan">
+                <default-provider>default</default-provider>
+                <provider name="default" enabled="true">
+                    <properties>
+                        <property name="cacheContainer" value="java:jboss/infinispan/container/keycloak"/>
+                    </properties>
+                </provider>
+            </spi>
+            <spi name="jta-lookup">
+                <default-provider>${keycloak.jta.lookup.provider:jboss}</default-provider>
+                <provider name="jboss" enabled="true"/>
+            </spi>
+            <spi name="publicKeyStorage">
+                <provider name="infinispan" enabled="true">
+                    <properties>
+                        <property name="minTimeBetweenRequests" value="10"/>
+                    </properties>
+                </provider>
+            </spi>
+            <spi name="x509cert-lookup">
+                <default-provider>${keycloak.x509cert.lookup.provider:default}</default-provider>
+                <provider name="default" enabled="true"/>
+            </spi>
+            <spi name="hostname">
+                <default-provider>default</default-provider>
+                <provider name="default" enabled="true">
+                    <properties>
+                        <property name="frontendUrl" value="${keycloak.frontendUrl:}"/>
+                        <property name="forceBackendUrlToFrontendUrl" value="false"/>
+                    </properties>
+                </provider>
+            </spi>
+        </subsystem>
+    </profile>
+    <interfaces>
+        <interface name="management">
+            <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
+        </interface>
+        <interface name="public">
+            <inet-address value="${jboss.bind.address:127.0.0.1}"/>
+        </interface>
+    </interfaces>
+    <socket-binding-group name="standard-sockets" default-interface="public"
+                          port-offset="${jboss.socket.binding.port-offset:0}">
+        <socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
+        <socket-binding name="http" port="${jboss.http.port:8080}"/>
+        <socket-binding name="https" port="${jboss.https.port:8443}"/>
+        <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
+        <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
+        <socket-binding name="txn-recovery-environment" port="4712"/>
+        <socket-binding name="txn-status-manager" port="4713"/>
+        <outbound-socket-binding name="mail-smtp">
+            <remote-destination host="localhost" port="25"/>
+        </outbound-socket-binding>
+    </socket-binding-group>
+</server>
diff --git a/ansible/roles/keycloak/templates/vhost.conf.j2 b/ansible/roles/keycloak/templates/vhost.conf.j2
new file mode 100644
index 000000000..b03a0dcf0
--- /dev/null
+++ b/ansible/roles/keycloak/templates/vhost.conf.j2
@@ -0,0 +1,52 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+
+<VirtualHost *:80>
+    ServerName {{ keycloak_vhost_servername }}
+    
+    ## Redirect all http traffic to https
+    RewriteEngine On
+    RewriteCond %{HTTPS} off
+    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
+</VirtualHost>
+
+<VirtualHost *:443>
+    ServerName {{ keycloak_vhost_servername }}
+
+    RequestHeader set X-Forwarded-Proto "https"
+    ProxyPass / "http://localhost:8080/"
+    ProxyPassReverse / "http://localhost:8080/"
+    ProxyPreserveHost On
+    # See https://issues.redhat.com/browse/KEYCLOAK-3067 for more info
+    LimitRequestFieldSize 65536
+
+    ErrorLog /var/log/httpd/keycloak.error.log
+    CustomLog /var/log/httpd/keycloak.requests.log combined
+
+    SSLEngine on
+    # Disable SSLv3 which is vulnerable to the POODLE attack
+    SSLProtocol All -SSLv2 -SSLv3
+    # Created cert with certbot:
+    #   certbot --apache certonly -d iamdev.scigap.org
+    SSLCertificateFile {{ keycloak_ssl_certificate_file }}
+    SSLCertificateChainFile {{ keycloak_ssl_certificate_chain_file }}
+    SSLCertificateKeyFile {{ keycloak_ssl_certificate_key_file }}
+</VirtualHost>
diff --git a/ansible/roles/migrate_db/tasks/main.yml b/ansible/roles/migrate_db/tasks/main.yml
new file mode 100644
index 000000000..db6ae4465
--- /dev/null
+++ b/ansible/roles/migrate_db/tasks/main.yml
@@ -0,0 +1,41 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: Copy mysql dump file from old server to master node
+  fetch:
+    src: /home/ubuntu/temp_backup/core_services_server_db_arch.sql
+    dest: tmp/
+    flat: yes
+  when: inventory_hostname == 'old_custos'
+
+- name: Copy postgresql dump file from old server to master node
+  fetch:
+    src: /home/ubuntu/temp_backup/postgresDB_arch.sql
+    dest: tmp/
+    flat: yes
+  when: inventory_hostname == 'old_keycloak'
+
+- name: Copy consul dump file from old server to master node
+  fetch:
+    src: /home/ubuntu/temp_backup/primary.snap
+    dest: tmp/
+    flat: yes
+  when: inventory_hostname == 'old_hashicorp'
diff --git a/ansible/roles/nginx/handlers/main.yml b/ansible/roles/nginx/handlers/main.yml
new file mode 100644
index 000000000..d99835134
--- /dev/null
+++ b/ansible/roles/nginx/handlers/main.yml
@@ -0,0 +1,25 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: restart nginx
+  service:
+    name: nginx
+    state: restarted
\ No newline at end of file
diff --git a/ansible/roles/nginx/tasks/main.yml b/ansible/roles/nginx/tasks/main.yml
new file mode 100644
index 000000000..99cf1e4f8
--- /dev/null
+++ b/ansible/roles/nginx/tasks/main.yml
@@ -0,0 +1,132 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: apt-get update
+  apt:
+    update_cache: yes
+    cache_valid_time: 86400
+  become: yes
+
+- name: install nginx
+  apt:
+    name: nginx
+    state: latest
+  become: yes
+
+- name: allow OpenSSH
+  ufw:
+    rule: allow
+    name: "OpenSSH"
+    state: enabled
+  become: yes
+
+# It is recommended to enable the most restrictive profile
+#  that will still allow the traffic you’ve configured.
+#  Right now, we will only need to allow traffic on port 80.
+- name: allow traffic on port 80
+  ufw:
+    rule: allow
+    name: "Nginx HTTP"
+    state: enabled # enable the ufw rule
+  become: yes
+
+- name: create www directory at "/var/www/{{ ansible_host }}"
+  file:
+    path: /var/www/{{ ansible_host }}
+    state: directory
+    mode: '0775'
+    owner: "{{ user }}"
+    group: "{{ group }}"
+  become: yes
+
+- name: copy sample index.html from {{ inventory_hostname }} to /var/www/{{ ansible_host }}/html
+  template: >
+    src={{ inventory_hostname }}/index.html.j2
+    dest="/var/www/{{ ansible_host }}/index.html"
+    owner="{{ user }}"
+    group="{{ group }}"
+    mode="u=rw,g=r,o=r"
+
+- name: delete default nginx config
+  file:
+    path: /etc/nginx/sites-enabled/default
+    state: absent
+  become: yes
+
+- name: copy nginx site.conf
+  template:
+    src: "{{ inventory_hostname }}/site.conf.j2"
+    dest: /etc/nginx/sites-available/{{ ansible_host }}
+    owner: root
+    group: root
+    mode: '0644'
+  become: yes
+
+- name: link sample html to sites-enabled directory
+  file:
+    src: /etc/nginx/sites-available/{{ ansible_host }}
+    dest: /etc/nginx/sites-enabled/{{ ansible_host }}
+    state: link
+  become: yes
+
+- name: adjust server_names_hash_bucket_size
+  template: >
+    src={{ inventory_hostname }}/nginx.conf.j2
+    dest="/etc/nginx/nginx.conf"
+    owner="{{ user }}"
+    group="{{ group }}"
+    mode="u=rw,g=r,o=r"
+  become: yes
+
+- name: allow HTTPS traffic
+  ufw:
+    rule: allow
+    name: "Nginx Full"
+    state: enabled # enable the ufw rule
+  become: yes
+
+- name: delete redundant Nginx HTTP
+  ufw:
+    rule: allow
+    name: "Nginx HTTP"
+    delete: yes
+    state: enabled # enable the ufw rule
+  become: yes
+
+- name: Restart nginx
+  service:
+    name: nginx
+    state: restarted
+  become: yes
+
+- name: install certbot
+  apt:
+    name:
+      - certbot
+      - python3-certbot-nginx
+    state: latest
+  become: yes
+
+- name: Create certs directory
+  ansible.builtin.file:
+    path: "{{ user_home }}/certs"
+    state: directory
+    mode: '0755'
diff --git a/ansible/roles/nginx/templates/custos/index.html.j2 b/ansible/roles/nginx/templates/custos/index.html.j2
new file mode 100644
index 000000000..da5a6b58a
--- /dev/null
+++ b/ansible/roles/nginx/templates/custos/index.html.j2
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>Welcome to your_domain!</title>
+    </head>
+    <body>
+        <h1>Success!  The your_domain server block is working!</h1>
+    </body>
+</html>
\ No newline at end of file
diff --git a/ansible/roles/nginx/templates/custos/nginx.conf.j2 b/ansible/roles/nginx/templates/custos/nginx.conf.j2
new file mode 100644
index 000000000..706278c7c
--- /dev/null
+++ b/ansible/roles/nginx/templates/custos/nginx.conf.j2
@@ -0,0 +1,85 @@
+user www-data;
+worker_processes auto;
+pid /run/nginx.pid;
+include /etc/nginx/modules-enabled/*.conf;
+
+events {
+	worker_connections 768;
+	# multi_accept on;
+}
+
+http {
+
+	##
+	# Basic Settings
+	##
+
+	sendfile on;
+	tcp_nopush on;
+	tcp_nodelay on;
+	keepalive_timeout 65;
+	types_hash_max_size 2048;
+	# server_tokens off;
+
+	server_names_hash_bucket_size 64;
+	# server_name_in_redirect off;
+
+	include /etc/nginx/mime.types;
+	default_type application/octet-stream;
+
+	##
+	# SSL Settings
+	##
+
+	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
+	ssl_prefer_server_ciphers on;
+
+	##
+	# Logging Settings
+	##
+
+	access_log /var/log/nginx/access.log;
+	error_log /var/log/nginx/error.log;
+
+	##
+	# Gzip Settings
+	##
+
+	gzip on;
+
+	# gzip_vary on;
+	# gzip_proxied any;
+	# gzip_comp_level 6;
+	# gzip_buffers 16 8k;
+	# gzip_http_version 1.1;
+	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+	##
+	# Virtual Host Configs
+	##
+
+	include /etc/nginx/conf.d/*.conf;
+	include /etc/nginx/sites-enabled/*;
+}
+
+
+#mail {
+#	# See sample authentication script at:
+#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
+#
+#	# auth_http localhost/auth.php;
+#	# pop3_capabilities "TOP" "USER";
+#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
+#
+#	server {
+#		listen     localhost:110;
+#		protocol   pop3;
+#		proxy      on;
+#	}
+#
+#	server {
+#		listen     localhost:143;
+#		protocol   imap;
+#		proxy      on;
+#	}
+#}
diff --git a/ansible/roles/nginx/templates/custos/site.conf.j2 b/ansible/roles/nginx/templates/custos/site.conf.j2
new file mode 100644
index 000000000..a76add09b
--- /dev/null
+++ b/ansible/roles/nginx/templates/custos/site.conf.j2
@@ -0,0 +1,15 @@
+server {
+  listen 80;
+  listen [::]:80;
+
+  listen 443 ssl;
+  ssl_certificate /etc/letsencrypt/live/{{ ansible_host }}/fullchain.pem;
+  ssl_certificate_key /etc/letsencrypt/live/{{ ansible_host }}/privkey.pem;
+
+  root /var/www/{{ ansible_host }}/html;
+  index index.html index.htm index.nginx-debian.html;
+  server_name {{ ansible_host }} www.{{ ansible_host }};
+  location / {
+    try_files $uri $uri/ =404;
+  }
+}
\ No newline at end of file
diff --git a/ansible/roles/nginx/templates/hashicorp/index.html.j2 b/ansible/roles/nginx/templates/hashicorp/index.html.j2
new file mode 100644
index 000000000..a557e65cd
--- /dev/null
+++ b/ansible/roles/nginx/templates/hashicorp/index.html.j2
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>Welcome to {{ inventory_hostname }}!</title>
+    </head>
+    <body>
+        <h1>Success!  The {{ inventory_hostname }} server block is working!</h1>
+    </body>
+</html>
\ No newline at end of file
diff --git a/ansible/roles/nginx/templates/hashicorp/nginx.conf.j2 b/ansible/roles/nginx/templates/hashicorp/nginx.conf.j2
new file mode 100644
index 000000000..706278c7c
--- /dev/null
+++ b/ansible/roles/nginx/templates/hashicorp/nginx.conf.j2
@@ -0,0 +1,85 @@
+user www-data;
+worker_processes auto;
+pid /run/nginx.pid;
+include /etc/nginx/modules-enabled/*.conf;
+
+events {
+	worker_connections 768;
+	# multi_accept on;
+}
+
+http {
+
+	##
+	# Basic Settings
+	##
+
+	sendfile on;
+	tcp_nopush on;
+	tcp_nodelay on;
+	keepalive_timeout 65;
+	types_hash_max_size 2048;
+	# server_tokens off;
+
+	server_names_hash_bucket_size 64;
+	# server_name_in_redirect off;
+
+	include /etc/nginx/mime.types;
+	default_type application/octet-stream;
+
+	##
+	# SSL Settings
+	##
+
+	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
+	ssl_prefer_server_ciphers on;
+
+	##
+	# Logging Settings
+	##
+
+	access_log /var/log/nginx/access.log;
+	error_log /var/log/nginx/error.log;
+
+	##
+	# Gzip Settings
+	##
+
+	gzip on;
+
+	# gzip_vary on;
+	# gzip_proxied any;
+	# gzip_comp_level 6;
+	# gzip_buffers 16 8k;
+	# gzip_http_version 1.1;
+	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+	##
+	# Virtual Host Configs
+	##
+
+	include /etc/nginx/conf.d/*.conf;
+	include /etc/nginx/sites-enabled/*;
+}
+
+
+#mail {
+#	# See sample authentication script at:
+#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
+#
+#	# auth_http localhost/auth.php;
+#	# pop3_capabilities "TOP" "USER";
+#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
+#
+#	server {
+#		listen     localhost:110;
+#		protocol   pop3;
+#		proxy      on;
+#	}
+#
+#	server {
+#		listen     localhost:143;
+#		protocol   imap;
+#		proxy      on;
+#	}
+#}
diff --git a/ansible/roles/nginx/templates/hashicorp/site.conf.j2 b/ansible/roles/nginx/templates/hashicorp/site.conf.j2
new file mode 100644
index 000000000..a76add09b
--- /dev/null
+++ b/ansible/roles/nginx/templates/hashicorp/site.conf.j2
@@ -0,0 +1,15 @@
+server {
+  listen 80;
+  listen [::]:80;
+
+  listen 443 ssl;
+  ssl_certificate /etc/letsencrypt/live/{{ ansible_host }}/fullchain.pem;
+  ssl_certificate_key /etc/letsencrypt/live/{{ ansible_host }}/privkey.pem;
+
+  root /var/www/{{ ansible_host }}/html;
+  index index.html index.htm index.nginx-debian.html;
+  server_name {{ ansible_host }} www.{{ ansible_host }};
+  location / {
+    try_files $uri $uri/ =404;
+  }
+}
\ No newline at end of file
diff --git a/ansible/roles/nginx/templates/keycloak/index.html.j2 b/ansible/roles/nginx/templates/keycloak/index.html.j2
new file mode 100644
index 000000000..da5a6b58a
--- /dev/null
+++ b/ansible/roles/nginx/templates/keycloak/index.html.j2
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>Welcome to your_domain!</title>
+    </head>
+    <body>
+        <h1>Success!  The your_domain server block is working!</h1>
+    </body>
+</html>
\ No newline at end of file
diff --git a/ansible/roles/nginx/templates/keycloak/nginx.conf.j2 b/ansible/roles/nginx/templates/keycloak/nginx.conf.j2
new file mode 100644
index 000000000..706278c7c
--- /dev/null
+++ b/ansible/roles/nginx/templates/keycloak/nginx.conf.j2
@@ -0,0 +1,85 @@
+user www-data;
+worker_processes auto;
+pid /run/nginx.pid;
+include /etc/nginx/modules-enabled/*.conf;
+
+events {
+	worker_connections 768;
+	# multi_accept on;
+}
+
+http {
+
+	##
+	# Basic Settings
+	##
+
+	sendfile on;
+	tcp_nopush on;
+	tcp_nodelay on;
+	keepalive_timeout 65;
+	types_hash_max_size 2048;
+	# server_tokens off;
+
+	server_names_hash_bucket_size 64;
+	# server_name_in_redirect off;
+
+	include /etc/nginx/mime.types;
+	default_type application/octet-stream;
+
+	##
+	# SSL Settings
+	##
+
+	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
+	ssl_prefer_server_ciphers on;
+
+	##
+	# Logging Settings
+	##
+
+	access_log /var/log/nginx/access.log;
+	error_log /var/log/nginx/error.log;
+
+	##
+	# Gzip Settings
+	##
+
+	gzip on;
+
+	# gzip_vary on;
+	# gzip_proxied any;
+	# gzip_comp_level 6;
+	# gzip_buffers 16 8k;
+	# gzip_http_version 1.1;
+	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+	##
+	# Virtual Host Configs
+	##
+
+	include /etc/nginx/conf.d/*.conf;
+	include /etc/nginx/sites-enabled/*;
+}
+
+
+#mail {
+#	# See sample authentication script at:
+#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
+#
+#	# auth_http localhost/auth.php;
+#	# pop3_capabilities "TOP" "USER";
+#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
+#
+#	server {
+#		listen     localhost:110;
+#		protocol   pop3;
+#		proxy      on;
+#	}
+#
+#	server {
+#		listen     localhost:143;
+#		protocol   imap;
+#		proxy      on;
+#	}
+#}
diff --git a/ansible/roles/nginx/templates/keycloak/site.conf.j2 b/ansible/roles/nginx/templates/keycloak/site.conf.j2
new file mode 100644
index 000000000..824d08a82
--- /dev/null
+++ b/ansible/roles/nginx/templates/keycloak/site.conf.j2
@@ -0,0 +1,33 @@
+upstream keycloak {
+  server localhost:8080 ;
+}
+server {
+   listen 80;
+   server_name bm-dev-2.usecustos.org;
+   return 301 https://bm-dev-2.usecustos.org$request_uri;
+}
+server {
+  listen 443 ssl;
+  server_name {{ ansible_host }};
+  ssl_certificate /etc/letsencrypt/live/{{ ansible_host }}/fullchain.pem;
+  ssl_certificate_key /etc/letsencrypt/live/{{ ansible_host }}/privkey.pem;
+  ssl_prefer_server_ciphers on;
+
+  add_header 'Access-Control-Allow-Origin' '*' always;
+  add_header 'Access-Control-Allow_Credentials' 'true';
+  add_header 'Access-Control-Allow-Headers' 'Authorization,authorization, Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,user-token';
+  add_header  'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
+  rewrite_log on;
+  error_log   /var/log/nginx/error.log;
+
+  location /auth {
+    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 https;
+    proxy_set_header X-Forwarded-Host $server_name;
+    proxy_pass         http://keycloak;
+    add_header Strict-Transport-Security "max-age=31536000" always;
+    add_header 'Content-Security-Policy' 'upgrade-insecure-requests';
+  }
+}
\ No newline at end of file
diff --git a/ansible/roles/pkcs12/tasks/main.yml b/ansible/roles/pkcs12/tasks/main.yml
new file mode 100644
index 000000000..b7d41728e
--- /dev/null
+++ b/ansible/roles/pkcs12/tasks/main.yml
@@ -0,0 +1,46 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: "create certs directory"
+  file:
+    path: /{{ user_home }}/certs
+    state: directory
+    mode: '0775'
+    owner: "{{ user }}"
+    group: "{{ group }}"
+
+#- name: Generate PKCS#12 file "{{ ansible_hostname }}-truststore"
+#  community.crypto.openssl_pkcs12:
+#    action: export
+#    path: /{{ user_home }}/certs/{{ pkcs12_filename }}
+#    friendly_name: "{{ ansible_host }}-truststore"
+#    privatekey_path: /etc/letsencrypt/live/{{ ansible_host }}/privkey.pem
+#    certificate_path: /etc/letsencrypt/live/{{ ansible_host }}/fullchain.pem
+#    state: present
+#    mode: 0777 #0700
+#    passphrase: "{{ pkcs12_passphrase }}"
+#  become: yes
+
+#- name: Remove PKCS#12 file
+#  community.crypto.openssl_pkcs12:
+#    path: /{{ user_home }}/certs/{{ pkcs12_filename }}
+#    state: absent
+#  become: yes
diff --git a/ansible/roles/vault/tasks/main.yml b/ansible/roles/vault/tasks/main.yml
new file mode 100644
index 000000000..46eddea54
--- /dev/null
+++ b/ansible/roles/vault/tasks/main.yml
@@ -0,0 +1,71 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: add gpg key
+  apt_key:
+    url: https://apt.releases.hashicorp.com/gpg
+    state: present
+  become: yes
+
+- name: add hashicorp linux repo
+  apt_repository:
+    repo: deb [arch=amd64] https://apt.releases.hashicorp.com {{ ansible_distribution_release }} main
+    state: present
+  become: yes
+
+# install vault
+- name: Install vault
+  apt:
+    name:
+      - vault
+  become: yes
+
+# configure vault backend with consul
+- name: Configure vault backend with consul
+  template: >
+    src=vault.hcl.j2
+    dest="/etc/vault.d/vault.hcl"
+    owner="{{ user }}"
+    group="{{ group }}"
+    mode="u=rw,g=r,o=r"
+  become: yes
+
+- name: Restart vault
+  ansible.builtin.service:
+    name: vault
+    state: restarted
+  become: yes
+
+- name: Copy vault.conf to /etc/nginx/conf.d
+  template:
+    src: vault.conf.j2
+    dest: /etc/nginx/conf.d/vault.conf
+    owner: root
+    group: root
+    mode: '0644'
+  become: yes
+
+- name: Restart nginx
+  service:
+    name: nginx
+    state: restarted
+  become: yes
+  tags: env_setup
\ No newline at end of file
diff --git a/ansible/roles/vault/templates/vault.conf.j2 b/ansible/roles/vault/templates/vault.conf.j2
new file mode 100644
index 000000000..2fec045b1
--- /dev/null
+++ b/ansible/roles/vault/templates/vault.conf.j2
@@ -0,0 +1,37 @@
+upstream vault {
+  server 127.0.0.1:8200;
+}
+server {
+   listen 80;
+   server_name {{ ansible_host }};
+   return 301 https://{{ ansible_host }}$request_uri;
+ }
+
+server {
+    listen 443 ssl;
+
+    # The host name to respond to
+    server_name        {{ ansible_host }};
+    ssl_certificate    /etc/letsencrypt/live/{{ ansible_host }}/fullchain.pem;
+    ssl_certificate_key /etc/letsencrypt/live/{{ ansible_host }}/privkey.pem;
+    ssl_prefer_server_ciphers on;
+
+    add_header 'Access-Control-Allow-Origin' '*' always;
+    add_header 'Access-Control-Allow_Credentials' 'true';
+    add_header 'Access-Control-Allow-Headers' 'Authorization,authorization, Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,user-token';
+    add_header  'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
+    rewrite_log on;
+    error_log   /var/log/nginx/error.log;
+
+ location /{
+    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 https;
+    proxy_set_header X-Forwarded-Host $server_name;
+    proxy_pass         http://vault;
+    add_header Strict-Transport-Security "max-age=31536000" always;
+    add_header 'Content-Security-Policy' 'upgrade-insecure-requests';
+}
+
+}
\ No newline at end of file
diff --git a/ansible/roles/vault/templates/vault.hcl.j2 b/ansible/roles/vault/templates/vault.hcl.j2
new file mode 100644
index 000000000..06054c34b
--- /dev/null
+++ b/ansible/roles/vault/templates/vault.hcl.j2
@@ -0,0 +1,49 @@
+# Full configuration options can be found at https://www.vaultproject.io/docs/configuration
+
+ui = true
+
+#mlock = true
+#disable_mlock = true
+
+#storage "file" {
+#  path = "/opt/vault/data"
+#}
+
+storage "consul" {
+  address = "127.0.0.1:8500"
+  path    = "vault/"
+}
+
+# HTTP listener
+listener "tcp" {
+  address = "127.0.0.1:8200"
+  tls_disable = 1
+  tls_cert_file = "/etc/letsencrypt/live/bm-dev-3.usecustos.org/fullchain.pem"
+  tls_key_file = "/etc/letsencrypt/live/bm-dev-3.usecustos.org/privkey.pem"
+}
+
+# HTTPS listener
+#listener "tcp" {
+#  address       = "0.0.0.0:8200"
+#  tls_cert_file = "/opt/vault/tls/tls.crt"
+#  tls_key_file  = "/opt/vault/tls/tls.key"
+#}
+
+# Enterprise license_path
+# This will be required for enterprise as of v1.8
+#license_path = "/etc/vault.d/vault.hclic"
+
+# Example AWS KMS auto unseal
+#seal "awskms" {
+#  region = "us-east-1"
+#  kms_key_id = "REPLACE-ME"
+#}
+
+# Example HSM auto unseal
+#seal "pkcs11" {
+#  lib            = "/usr/vault/lib/libCryptoki2_64.so"
+#  slot           = "0"
+#  pin            = "AAAA-BBBB-CCCC-DDDD"
+#  key_label      = "vault-hsm-key"
+#  hmac_key_label = "vault-hsm-hmac-key"
+#}
diff --git a/ansible/roles/zookeeper/handlers/main.yml b/ansible/roles/zookeeper/handlers/main.yml
new file mode 100644
index 000000000..a15d1b2ac
--- /dev/null
+++ b/ansible/roles/zookeeper/handlers/main.yml
@@ -0,0 +1,32 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+- name: start zookeeper
+  service: name=zookeeper state=started enabled=yes
+  become: yes
+
+- name: stop zookeeper
+  service: name=zookeeper state=stopped
+  become: yes
+
+- name: restart zookeeper
+  service: name=zookeeper state=restarted enabled=yes
+  become: yes
diff --git a/ansible/roles/zookeeper/tasks/main.yml b/ansible/roles/zookeeper/tasks/main.yml
new file mode 100644
index 000000000..8f86745e8
--- /dev/null
+++ b/ansible/roles/zookeeper/tasks/main.yml
@@ -0,0 +1,63 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+################################################################################
+# Setup and run Zookeeper
+- name: Download and unarchive zookeeper
+  unarchive: src="{{ zookeeper_url }}"
+      dest="{{ user_home }}"
+      copy=no
+      owner="{{ user }}"
+      group="{{ group }}"
+  become: yes
+
+- name: Copy zoo.cfg file
+  template: src=zoo.cfg.j2 dest="{{ zookeeper_dir }}/conf/zoo.cfg" owner="{{ user }}" group="{{ group }}" mode="u=rw,g=r,o=r"
+  notify:
+    - restart zookeeper
+  become: yes
+
+- name: Copy java.env file
+  template: src=java.env.j2 dest="{{ zookeeper_dir }}/conf/java.env" owner="{{ user }}" group="{{ group }}" mode="u=rw,g=r,o=r"
+  notify:
+    - restart zookeeper
+  become: yes
+
+- name: Check if systemd exists
+  stat: path=/usr/lib/systemd/system/
+  register: systemd_check
+  become: yes
+
+- name: Systemd script.
+  template: src=zookeeper.service.j2 dest=/usr/lib/systemd/system/zookeeper.service
+  when: systemd_check.stat.exists == true
+  notify:
+    - restart zookeeper
+  become: yes
+
+- name: reload systemd daemons
+  command: systemctl daemon-reload
+  become: yes
+
+- name: restart zookeeper
+  service: name=zookeeper state=restarted enabled=yes
+  become: yes
+...
diff --git a/ansible/roles/zookeeper/templates/java.env.j2 b/ansible/roles/zookeeper/templates/java.env.j2
new file mode 100644
index 000000000..356192c81
--- /dev/null
+++ b/ansible/roles/zookeeper/templates/java.env.j2
@@ -0,0 +1,1 @@
+export ZOO_LOG_DIR={{ zookeeper_dir }}/logs
\ No newline at end of file
diff --git a/ansible/roles/zookeeper/templates/zoo.cfg.j2 b/ansible/roles/zookeeper/templates/zoo.cfg.j2
new file mode 100644
index 000000000..0c40776b9
--- /dev/null
+++ b/ansible/roles/zookeeper/templates/zoo.cfg.j2
@@ -0,0 +1,28 @@
+# The number of milliseconds of each tick
+tickTime={{tick_time}}
+# The number of ticks that the initial
+# synchronization phase can take
+initLimit={{init_limit}}
+# The number of ticks that can pass between
+# sending a request and getting an acknowledgement
+syncLimit={{sync_limit}}
+# the directory where the snapshot is stored.
+# do not use /tmp for storage, /tmp here is just
+# example sakes.
+dataDir={{zookeeper_data_dir}}
+# the port at which the clients will connect
+clientPort={{ client_port }}
+# the maximum number of client connections.
+# increase this if you need to handle more clients
+#maxClientCnxns=60
+#
+# Be sure to read the maintenance section of the
+# administrator guide before turning on autopurge.
+#
+# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
+#
+# The number of snapshots to retain in dataDir
+autopurge.snapRetainCount=3
+# Purge task interval in hours
+# Set to "0" to disable auto purge feature
+autopurge.purgeInterval=1
diff --git a/ansible/roles/zookeeper/templates/zookeeper.service.j2 b/ansible/roles/zookeeper/templates/zookeeper.service.j2
new file mode 100644
index 000000000..8e6ea2a2e
--- /dev/null
+++ b/ansible/roles/zookeeper/templates/zookeeper.service.j2
@@ -0,0 +1,16 @@
+# {{ansible_managed}}
+
+[Unit]
+Description=ZooKeeper
+
+
+[Service]
+Type=forking
+ExecStart={{zookeeper_dir}}/bin/zkServer.sh start
+ExecStop={{ zookeeper_dir }}/bin/zkServer.sh stop
+Restart=always
+TimeoutSec=300
+User={{ user }}
+
+[Install]
+WantedBy=multi-user.target
diff --git a/ansible/roles/zookeeper/vars/main.yml b/ansible/roles/zookeeper/vars/main.yml
new file mode 100644
index 000000000..617133449
--- /dev/null
+++ b/ansible/roles/zookeeper/vars/main.yml
@@ -0,0 +1,37 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+#Variables associated with this role
+# zookeeper related variable
+zookeeper_version: 3.4.8
+zookeeper_url: http://archive.apache.org/dist/zookeeper/zookeeper-{{zookeeper_version}}/zookeeper-{{zookeeper_version}}.tar.gz
+
+apt_cache_timeout: 3600
+client_port: "{{ zookeeper_client_port }}" 
+init_limit: 5
+sync_limit: 2
+tick_time: 2000
+data_dir: /var/lib/zookeeper
+log_dir: /var/log/zookeeper
+zookeeper_dir: "{{ user_home }}/zookeeper-{{zookeeper_version}}"
+zookeeper_data_dir: "{{ zookeeper_dir }}/data"
+
+...
diff --git a/pom.xml b/pom.xml
index 8ef92911a..95f63d4f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -660,7 +660,7 @@
         <mysql.connector.java>8.0.18</mysql.connector.java>
         <javax.persistance>1.0.2</javax.persistance>
 
-        <keycloak.admin.version>9.0.2</keycloak.admin.version>
+        <keycloak.admin.version>20.0.1</keycloak.admin.version>
 
         <reasteasy.client.version>3.0.14.Final</reasteasy.client.version>
 


Test patch:
diff --git a/ansible/inventories/test/group_vars/all/vars.yml b/ansible/inventories/test/group_vars/all/vars.yml
new file mode 100644
index 000000000..921db6b0b
--- /dev/null
+++ b/ansible/inventories/test/group_vars/all/vars.yml
@@ -0,0 +1,73 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+ansible_connection: ssh
+
+user: exouser
+group: exouser
+user_home: "/home/{{ user }}"
+
+# Domain names for VMs
+keycloak_domain: "{{ hostvars['keycloak']['domain'] }}"
+hashicorp_domain: "{{ hostvars['hashicorp']['domain'] }}"
+custos_domain: "{{ hostvars['custos']['domain'] }}"
+
+# deployment related variables
+custos_deployment_dir: "{{ user_home }}/custos-deployment"
+custos_source_dir: "{{ user_home }}/custos-source"
+custos_repo: "https://github.com/apache/airavata-custos.git"
+custos_git_branch: ansible-baremetal
+custos_integration_services_source_dir: "{{ user_home }}/custos_integration_services_source"
+custos_core_services_source_dir: "{{ user_home }}/custos_core_services_source"
+custos_distribution_version: 1.1-SNAPSHOT
+
+# kafka variables
+kafka_listener_port: 9092
+kafka_url: "{{ ansible_host }}:9092"
+zookeeper_client_port: 2181
+zookeeper_connection_url: localhost:2181
+zookeeper_connection_timeout: 18000
+
+custos_host: "{{ hostvars['custos'].ansible_host }}"
+custos_port: 31499
+
+#Keycloak
+keycloak_vhost_servername: "{{ hostvars['keycloak'].ansible_host }}"
+keycloak_repo: https://github.com/keycloak/keycloak.git
+keycloak_source_dir: "{{ user_home }}/keycloak-source"
+keycloak_source_dir_new: "{{ user_home }}/keycloak-source"
+
+# Database related variables
+db_name: core_services_server_db
+
+sharing_subnets:
+  - "149.165.152.112/16"
+#  - "140.182.0.0/16"
+#  - "149.165.0.0/16"
+#  - "192.68.133.0/24"
+#  - "192.12.206.0/24"
+#  - "149.159.0.0/16"
+#  - "156.56.0.0/16"
+#  - "149.161.0.0/16"
+#  - "149.160.0.0/16"
+#  - "149.166.0.0/16"
+#  - "134.68.0.0/16"
+#  - "129.79.0.0/16"
diff --git a/ansible/inventories/test/group_vars/all/vault.yml b/ansible/inventories/test/group_vars/all/vault.yml
new file mode 100644
index 000000000..0534770b1
--- /dev/null
+++ b/ansible/inventories/test/group_vars/all/vault.yml
@@ -0,0 +1,346 @@
+$ANSIBLE_VAULT;1.1;AES256
+61653738303930653131613961663863356534323830303139623430613232646230373534643865
+6662346166343934323233353631323038326535643530640a383963623931333661336137386661
+38373235383735396333666663313064326335356134313031343037633566633135343336373337
+3637326130356239370a383837396466613631313636653266303039323239666135616137303335
+66383939653766373833306264373065373263393132626237346663636433363963343137386537
+66313337393836383934633732646138306664373664356462316530396262383865323263653037
+34333031356562623865613933396266623162396438323465383932303161353063626536636432
+36336137653133363265363331323563326135363439616330643166653934346237663738353761
+31343834363539613063623366323737366166346335373266303434626430646561393466663139
+30313864326463386637646237376438613532376339333734353761626136653462353038376665
+38633563336630333361333965626439616234656435323034633934353138643261376261333665
+34323361353965313265323964306237356534393038313737353731306430643333373462383339
+30383631346539323266333435636133666238356663303533663037623237653739383736616532
+61653266333037373561643938303630633066643134646534303034303637393238666163303039
+31343734356430313562383937373265393532363737613561353664313436626462363465386331
+34663263653639613263393065346364306264626562323338663464643363306233636334393466
+64633338643138616537313332356663333234373664326233346161323731373431373565623461
+36623331616132613962343066393239386564313239316663646231653164626366613634633735
+31333963373938666335333032363765363663353037303638316665626530343030386439353236
+61383634656639653464306665336636633062396130653563646537343236336135383831333665
+37323539333665386137346638323739656261383833393130623765363465396535643266623963
+65323866376230313931313239366237313735653135623832393637633466306262346539386231
+66333039663231396431643835386237373932313433326433353030626266663365666439626530
+35353061373663376438653837393261373034626438313866323161376661383337656364376533
+31643764326231376364353262333530386435656633303262303832653334373337613935333363
+66636136613766363965386637366265306438656465663330363166373037633936363036663536
+34306331386533333532653730623864356634333432373965336464663062313861393036326634
+39663839306139366434623835623664363339363635393465313937643931396434353764353163
+33643130643464386137623334656163653166393732646539663962313736663164393536613630
+62616438333834643737373934346634323837613734343763383433313964663435303537663161
+30636638386265626139613234376231306266363238353934616361363462633662653035343363
+66666635306465636634353438323338666164353332663962363064663732643530336163323431
+64316131373364353863316661666331353231616532636438353238376632366136626565653664
+39303635373862326163623139616462616331643939663464313261393562363235643739373035
+33663662653862323264383139643566353662346533383535393666636461303062353261623035
+32313962613163326236366433336364393138633133306366383061663261666662623432666436
+65396539613461613563363437326436373731353735616636333465393964636635373537303463
+62633934666439303137323339393062616264366130633665666333626239626138373633303533
+30646361636636373833633862323030333432613232333737336330616366343162613235633737
+33363233326562343165356666396336623632313033376131623164393265613432623462623031
+64653038666635343231633438383866366434336439363937303730646162616134396632303933
+61366631313934333861326561653661653732623532363466313335303765663262633034356238
+31343035333234653666643766326132613239633033366661353466383261633936353539376635
+63616536313636373033333334313138373931336434656261643331336334353966373732376236
+36666637396633306534313863663565326330366533643663376435613132323634666665616461
+39663366623937363734306266336135663339613664313939383665343430306462623031346332
+31646630623466333236303132316636306264653439393636633161316239353934343863326131
+32666462333330663938623536633566366664393964633330633832353231353139346336396130
+37316461623032383538356338336632303834393435373739316332343738373864303262393765
+34316661643834383530313834336334323439663363323533623437373435663330613766663361
+34613338356566633665343031613065383236623739626333383730373965633361323966376130
+35613831363733613065613832363534353262666266343431313338303537653663646532366339
+36323833643266353136613566306564646162333862616339353734336663336235653236363064
+64383531613038383733653033663766313663613161633663383332303839646134366130386337
+38643465653232656236356165326365393833366535356433346337326532653332336631303939
+65393063373234653734386338363437613063343964316362376435363766663237613334623238
+30653036356239396461623939646231633064333964653138323864363336666137333736373530
+33376664383863636237366232393339623265613562643262303935396464646334633636633038
+31646432356465396631393366663231663434643765663764633762643065626535633838363963
+36663665643165343630663266656461386632646561663864373639633961623365633561316466
+65336439393534373364316665626639316662653530373533383031363239323135386666656234
+66643961366238393062353039626430653430303435663662373837653435633038373932366662
+31303766303764376435353937326365336134313665313639656531613164346363643830343335
+36616138356165663934626166643939663966393966343563373733333466626661316463393730
+61646531656634633766633835303031333663643732663334393765633538653161653661613532
+31313230346534633566663864326530636666336563363437666637613138303631616635386636
+38323561333030353563646463333130303133366466383034353137653338386563393261666532
+31666635333535656337353235653165383264303337393066386436373839616666646637363434
+63306431623734303161383964623238656362353362306265323161666532303230663165653139
+30363639373566373630613161313030383037303636646332626562343365633764616135663933
+37643663633532653037313639383734343639623765363666656330366263626666386234613638
+64313833336431393565656233613836613530383566313534366332663337343164656530363564
+39383735373731646337663730613461623062323030323139393135626132393339656335396630
+61383763616465306439396538653638613339393932666265343066356635346161323563376337
+64313761646430313863623366613363303737643935653765373463653962626265313461343531
+63366330366364323431386637643232393832373339626265656636633163616566646335353564
+62326463636438393362383563653563656130373938636365366162616461366235313530643336
+39376164363230303061383633313833343563373863303939626136643136643234303738633336
+33303239646230393765393235383464626562633663633938333236333931613639363038373639
+38353134373135626265343131613061333735386638613662363332356664326564313661323863
+36356364353030636231376233333836343534363135303432383266653037326435323037393930
+35353834623338636638616534356535656338336461643734643238666631633864303436323561
+32366431623737393034336234653264306438353838623838333466346466643933656435393830
+64346634333631623336353736376633636332316666333534313739616563353934343364383766
+36633837653939623739333366303161323135626236346637343437323732626438623962383864
+30656161383336376533633430333162376130393639386164336337666165336466613031653634
+30373864626631393130616361333536393763313365323731373036633531386262376335346361
+35323661303464366535373366373366376662373938383561643339633830336131623565326137
+66313638636562366236616663643130316531373937623361313837353863383131313736613363
+64376464326464633363353164346165396365363438343265393361626532383738393866623133
+34393139643762336364623565373230663736396362353363633134336335313336363761363439
+30653033323965653534366439633630373962666637643236643461636165303862393836353063
+34623833626635656463343430636334636335366561643866633162313032353233323338373464
+61383533343831646337326361343131663566646565303535616165656334383264326334653837
+63316532643561373034616564663961646366303866663862626639623061613034393364303163
+63373463393135326363623761613563323030323535656331616133363434633739666131376161
+38333537306630643764626535666130316137396638343733363666333761623264393036303562
+64396332353832353832336639623264333361353539623637616433303630356665396136326261
+33386265303931363434626231326539336131386331356130316361643237316330666464366431
+36623563653939613732316636323639373565353136303661613238613364393032316632383538
+64396162336138343837356235346366326566633632626365643832373138333834323664313166
+38633135393161336464363832333430646465616231653365343833663866303362323463633030
+65336265323931303230346133343863346330316139613264613535343637643832636539396534
+61323238366232623333323832323033353461643365353536353763383838616335303864303430
+35326639663562643838323132396262616438383934646437313665616539663631346235373063
+61636462663962636565623337363236346166626561326162336364323031303232663530633138
+35313034343731376637366135663066306363643363353035346331363338383836623235363837
+63326533363561663166623437636465326461653361386563323637366662326433373834636465
+36616536373265383130316134303561633466366531333338616537353832666435333563373431
+31306136303132306564356532663136626164656638353362623130633533363361353035633933
+38383337633733316336653765316239616331663332373264636235393134353666303039356134
+64313737626435303936633632313265323538353739613634653162373665633162356434393738
+65613563653239663661653937666664316338326265316264633733363963373563393835656664
+36656131376364613534656336346363323634643439353362633534356537323231323536376539
+34386564303239306130633939646537306466623330343065306130376337316537306461333030
+64323630666638373962363636363162613937323763393661333966356465346431613430633635
+35386461316435393963396532316236653263393032643763313161363130333331373634666634
+39373735646334663432623531343935623263393830623262616361653833616463356663313730
+34376163626430356232396361633133303430333838356531383264623566376562343530366137
+61393764656466653430646665383066653130643961363862376334383764343164356233646133
+61646536653636643137643231623363326236356237353862616637333862633966626237626433
+36633665396638396638363065356664646630353432613038356166663834613839323438633966
+37376137653766613061386532343962323661663766626536393464653730363636363130643535
+37646636303366633334616335393033313662646135393238333435316365373066303431396238
+36353163393362643363333262333230353630363330303661636134653239353365653836353730
+37366263386632666534653661356263643363386565343235363265376336393937363736366431
+33666437393631376662363865383966623932653364313239373430333030656137326530373465
+34636234336136333435376338396430356232616638393763313231313831636332346165353265
+37623634633538653962616361303566396665373036386339373232653137303138613063353936
+61656661613564303931653937343334333732616239633232613863383563373234353032313737
+31643833663331633636623737633466656335633236623234653030386530633239613433653335
+63663466353531373463656163323563666233343936363561353763653138353865386330306230
+35386438386233303063313532663363373161663833346332316635633432336464666139366163
+36316165626166616438383030376661316635306536616135383664313630383735383166306230
+37393738643934636233386430396530346532623536616361656637316538343064336337613233
+61633763313934656637366662363532653138313163376136616136653838656166373132646366
+65356634386639383334393964663936343065343934323234316266613632633636363365383335
+30383064626239333537653632643033343161613061343663396339333538396131386263656236
+61383230666338656135333162383062346463333132626362393935333836633837666261353930
+39636133376635353763343036363736353164333166356163386161386538626135383363343030
+33333063323931663764343239613564633366646235306432656463663237616439613436303962
+65366362636535663730323633373033313230396239386634313139333135333862313032316639
+66333832333233363164663263363866663430363630316631663061646330616261623965633138
+33393235356666616430386432666462376164626564363339663431306238636631383430366264
+61333238643464623564633066316162626639653933313834336238636163633230363263323964
+34303866653665343831303862666135633762383161616336356164343933626261653632393836
+31373736643133396661663030653737336637663565356433303238613834396132396636613137
+39376535373837306332393230343139386261323835313561613530643235393234303030366636
+61356463643635303465656332333363396637323865333264643330663661666536393434616136
+39633462373933353332646230316637313633343836386662383436383264306661376234343265
+31353966663333626565646264616336626337346162363434373333353466626165656436386139
+63373233363037303238366566366134313564646335363565326138303834396435326339666431
+64663038653461326133353731653265376630663931643662666164666638643939343431383230
+38353561623736633462353837656336393139353435323965363630623234623264643239626534
+32303565616261613066346464643230333132616638333933613035343532393839613236633262
+34356262323639653164326166393134353565356536666135393766353934643630336165356366
+35316564653031636231333562396162323338613835663261306635613864393131363031656630
+38663535633938323638663964373933366435353334383964343663353934343761633339333336
+33393636653264383662323766373534313132356262626537613264376161363331313930333439
+39313735386661613966626432333461336366653438613033373832623430363735356161313762
+31666462363963333032386634613036373162626465643930323636326432643330663434313432
+66323739306566323631363637616166373631356562663732313663316234393264623465336130
+32333537623935626633633462346234633162396533383437386238623564363361356664383738
+61353163383239346363353230653730663065383636326434656239323265383133613666343061
+63373238623836626230343364633165653962353535633062636430376430363566363137656163
+32396230376364356330623232386165373964633937303036363237633662303437653630643434
+34303332333466303662626530646462363062376530336438363632356439653262623366653332
+37613963316564643364653232373330356266623239346365613236636565373637633439653730
+32373635336661613139623832323061373832653530353831316235656261306661393833386266
+31383832643834383839626632633564613731313564616662636166366431616162346666366662
+37636261663233636532356436383638653835376134653166663063346466343764303535633738
+66303562643539356266353563616462306663336139633139386237646265633364313431656535
+63303632383462383235393464333938336161373030383034343138343830323739306335636561
+66623966363036356337653730363965303836356630643365333162613265613464623430303466
+38393537623162633133623363346531633432346237643839366138343964323431383963336133
+66323766643365363536636231636565343766613535626530653962343736373632656230316164
+31373762326665633361333766646565396631353036616338363363353230306237393063306463
+62336264336166383030643830373131333835353864636435383662353238393430373365626538
+36643132656539393964623537663863636137343066333961393863336539303838303164373536
+65303435333566626332346666323161353665386533646639366432396262363161343730313333
+62303063303730333461356661646238366266323131656662303539663864666266653132613130
+39623532373130646637373466313362663666653533346235383163333437333463663065616537
+38383737353732316631626665393039373238623866613863633031343031333533396263353033
+62653035356166393462616466383366306533326666346233613833336639373937396534313937
+39643934343665353436653734373432396537373463653361363063393836613964373036333161
+64663337323033386262643835383166633361363462363233613835663665366565643933643331
+66326433366639323235366537616330313937336563643331643135333336393866376563643562
+39353938656232393165636263643731396662313338373661323464353566356634626133303837
+30643264636465626339363861383938333434366462396634306265383534306639343963643037
+66633436633734386436666364303433663339613638316365346264646138303836343237643163
+31393634633461653463653063373031343038396365653136663436353234386633396135383939
+36643365343637356630666565383266643838373537623166323937346136656233346264316330
+37343363626139323266383065393831636535313634323466643065313831313837623738326661
+33633831643061396238333165613466666238373930626561326665326133306363396262303937
+65363639316337633266316363636561353465343536656365363332386462353334323965346530
+61326534383263343538303766663661333163643865383863383565303238313963633630346533
+31646362373761376637333332376530626533376661333337636432303335623564393138376661
+35386361663862316138303261346164663037313962393539653130386434636264396263343537
+63353536316462353531643131323737353939643738633766623063343361366438626534646630
+62346633323432636637626565366530363766313435333737613838343034343732373838643161
+39313863336564613961333839633737383637343234383965666638623732383633313261313332
+63643434333964333631336261333839383636323763656262663130343661313036666361636562
+34313263383464333664353364306663303130366233363062356236626233306131386137636161
+37346562303763316661616539633031356161323833386636366434383761383561303736356335
+64333935386434313332326431333261646564356432396335313064323165666234613761313035
+35306663366562376136313733383336623231346435343130663438353765343036383765303137
+38336439656562653734386663333232326662306663653962633963333532313130373631653530
+34623632616266366366303832646335643037666137353836366163393538333063383037373839
+31623563336164343938333362316536653965316164643131636362376334373164653138663666
+30363832366235356563613632636539656632346664306135663265643839663465623537303739
+30393336316535613364663931363136656439343730396266356566626663346533323462336565
+32323138396330633434333938643135633933646564643431653062383838303835613663313265
+38323036333636393132333362336366636366366137633731636566306434393465336364353235
+65383332643530613864343531663937373563373061313439626461383961613066656462613263
+63653262343435386532303363323666333434386234313337616465656363373938633661663665
+39313133346263306139333732363861633336656232373833633630313437383930653734653132
+38396531303662383031353232333164646232646164393536613534353137356430616564333133
+35643761626132363264336563396330323266666162643539356264333532313463336134353937
+61616461353035626238373939616563323461653864643665346634653265363332326538343235
+37653036353638343266626331636236303466306239386338643463376465313666646330396438
+33656633343232313464336533653466373365326532346565326530343036663338373965616237
+32326365383761313363306338616539353461626462393061313638633335343830663264373736
+39623138326533393363323634663230393766633537306436353163343536613539323462386331
+62613236353432653839623862343963343537306339336366613638663534333663383431633164
+38653930623763343933356630313234323030323638326564386631643136323766353131356638
+66393466393833336235303862343963613935343161353535336161373533303334643639633265
+65643933373937303737353938366632313163343635363131303731656561383434356533666130
+38326433656432653563306465623664663732303538376338626665343361633830343862396139
+36306165626336366434373730313966353038323230323163323362626136633339343762626334
+31353936316263396263333931393033643566393737656465323539646531393432663561386338
+30346361323336303030613964326665363836316536363637376639346236303963353266353835
+38303730343435326430363432393739343565666635653930623531663462306538666630333461
+61396236626538616265636334323065656136396531636561393761613864623564636463613832
+38316162626331343761316233613135393961313462343734613230616531373339636564356436
+35626331386138323337386365326534336661646337373230373965366337383737356131643136
+61383961643862623636336537386364306664396365333635323866626130633132353639636433
+63623066393834636338366161393830643238626532343034616539623530316537303034353531
+36343538323039356235386161316632343465353763363633373134383937623061363837656239
+31613136333434663832383464616164383830393533313466353564643432333663386262303833
+30346338386331373261366131616563623565626130626666303932616633643162636462646636
+34316238626430363563366630663734643835643938623861663339386134333662383330316337
+61373435623166383038303337306139393461646530333333366365636130326633313936326436
+66636533613737616661383161636664353865333531633862356530333563643931616165386134
+64363562313230616263636435343165343132393266326366346432663732636532626435386530
+65393837386561643661313531613839656236396163383065366137373236343734653534323832
+61376262643438306539353338636234373637646265653064616262313863363065653737633861
+66333039343633633530366566656462323039623137613238383138653165613339356237653534
+38376139373563616365363437326136373165323938386535303034396331333331646438336637
+39383831666236633263613661306566613438346564326366333235363463313634363037633463
+30353265386362386434303465636362643038346138383066613464363432353064333865326361
+38356232343536613039393133653934393736363539373933306137363631323038653737646164
+63383832333963343934386433396436633739356263656164363631633037306366636133363239
+30356366393663383763626661656335333064626264333031353632383236333531343962353332
+66663838303161376265656264393862646530646137343635393039633833653335346366633163
+61663662663433633265386135333534353131653632386137663435316338646536383566383239
+35623839616330346135316261313036353033646631633731623336303630653137616435373032
+35383665356436326164623164663861376637643239316132383133346663353665383861393865
+66316163616166636433326237373931643039633139303536353436626365333362336236663337
+66663764363066656262616564613836643966383165343238666534363734623066643761373934
+31393934653662306566323032636163323238306364313761383465383532613432633966383136
+62666336373231326463353064343730376466613862626535373935366231386161313763393662
+62316538393030333530363265323361386438316639633966666161303065323337326539336339
+66316631656566353865313338323333306365333632396538353666326130643030343530633831
+31363566383436626439353234633563353233316538646666376534323637666362623065313438
+37646161366430633932623537373032623635663332303761333063663666646338386261336432
+33656438646636653063613938363966356431666236376339393965336234616337303661663833
+38636431373737306131363830643738343464613162633630373433636432643562626132633162
+62393561343137356266653438313061363464333734343536383631613834363166323131303732
+62346362376561353362383962316335396631613031333761363031396162393139653132633131
+66623561303866666263663438393332316363353735643132613033316131373666366232643131
+30326434626331666238366464616430336264363535393264633565626633363932363562666463
+61303563633262336636656665393762363663356132373164313135356161393139333835373034
+63333533663337333338323231643936323865323836623964323933376361373132666365653966
+64316638306339316666666363313336666332643131386631363033333739616535646364333932
+63313065613930663430333637646439393537633664303534633566663232303438366538653531
+62303162303065613930336661626633316338326337633462313335303732616466613666643765
+64316635346266393232383934383335336633663737343964356535303536333166306266343834
+38396431323737623130643063386238666332346438343131353738373835663231623636346661
+37636632333362643238613934636261663262393837326130386564646361626161663832323939
+31353561313361326462666134306164393239383935643766313938323561313538613235663130
+65393732383030656262663935373239373733373063656362346562343265396437666164346263
+66306666636431353861376561633063313165663738666266306439313061383330666466663865
+39386362636561653438363137656338653035396664633435366238646232626161623562666264
+39303364616361643135306331613165623938393538346661343337393663623663363964386261
+64323332386334326330623961383935633533306165343134663931663065653361346632366537
+65366463313166313566666431636535663961343433373466343539396530313335653233653964
+39376361623438633534396136303962343532633838313137316635626362373931346164623634
+66333764636632353764303136386266616464633562386633393936356437643735353832353366
+37343965356431356464613864616336316637373961656533396137306534383966613139363066
+64663664383765313566376535613737346365663935353533623862383463633232343666303239
+33666266396166323461313433613034636631353239383939633237356539373831346139323865
+62313366343435346335616162353931336663313862303332616334323137343266323665653534
+39383131323261623033383536393763626534396261396431616565333566373637313630663339
+62643138383562333936613630313534333566633230626632396132656638306637373839306438
+34346438383638313636313331313762306238373330306266623532373966383661346132636564
+30633364343834363362386261626561643731323131353366396539626236653936656532616631
+32623530356131363235333966633637646339366166356235313263363639346530303036636439
+36643736353238346261363334373734343630363062316335636466326331336361386562613365
+38346232636333326634343938303461353836353332316665393865393331356135316131313139
+65363262363533363633393338393035366236363864353233663633373239653532346630353937
+30643830653733326235653561653438336235383062383535653936333461313734353132613838
+61303533303836333039666233323235346535383864323737643265373965393536363766643763
+30636239303761646466383732643465643865393263646465313764653131326536636537303838
+31356339336466393533306538613465643664656364363761613462643464646639333234333466
+33393865643564376661663235623136366535623434663436376533623364633630386536393331
+65353162306539313737633363343435323738333561333930356362636530643364613638323738
+66616466333431626565653037383432616231646462333934373132383232663232346237633338
+35653235393639616130623138366639346163393137363665623261303635663835333839613035
+37303462356666646262373161336638313738613137393132343461333764333839653135623364
+36633661363565323831623731336364626436663934623532393864336463333932343535313337
+32383331633133343737313062313836333163323865333130636536616565663461666636353263
+37393631646530616265323164666632383062363135333833393733346635613862343132663530
+65626537663662623330393364333765343164613366643165643937343563313264636163623761
+37313333633634303035313262626234396336376461336637643036326465643339323636363466
+34613761353135376538633864353635346663393265366230636335343762663939643463313865
+64386430323363633533383964666631366162646361313337666138313062353662393438383862
+66393732623033643062346330356433376435373935343564336634666531363430396236626534
+37653162356330633832383130333863393832643031643362343565393237343730633630393839
+66646332333835613066316239333239656637313739373266393338313630623534353836613564
+38366631363034306266383231346266613735313365373034396637373666373037343235353634
+66353937653630366166323366323538323330326634336461326466363162376335626565666434
+36313333636262333465316335623964346133616536663765663330363232376364663966386461
+37353234326163393264383232623763633435303136353237326539636132356563393632653531
+65313736373261383962386364373831393139383432653134616438643032383931383532623833
+61313765663331366265386536333937323461393163306539633839616161633861323933626237
+30363636323934316361383538323938653738663961326365393239386235613935653262653035
+64366633363161363637386630626136643663623765633836656139313731316664336464663136
+30386535653766633962306131643766626231356433643533373632623039633564316662663561
+30326531343935373464633464313663383434356631303331626661363663653661373036366230
+63633261643133653733376564643238656566666264346665383432373465643230363434636239
+35616462633264303530343631623033396538636239373730383862613338333330306531323663
+38356533383731666332306434303465656437313166616461326237333139346134616665663534
+35313039386535396637373533643662623135393335386665373730326361343330613164333836
+65633565613236336263363931376439383664303666613834623036383930363565383165303832
+30366534346537323238386464623632346633616661383065353030376664383731383231366134
+31626365343061656165303537353331343664616135393634646238623563306566613533643132
+30343236663864313931323564346431323130323435643233343266643130353339393164316232
+34323937316530643431323936326435356230353661623362653561363062376636353430616339
+37653366363537366538353331613330646234373137376136376166323938616165333461393765
+62396266343136346237653332633833313034313761353238313662663563336134343932643133
+65323039656133323235323534623630613637346365383939356331323231633230316463643361
+32356239366662656335633264623233323364373762393139396162663861643939363765333563
+36313966313235396430363432313738343265666466626538353365653935383536366364326364
+35303932363630663066663264336232633135623336373531636461663636343330373231643832
+6362
diff --git a/ansible/inventories/test/host_vars/custos/vars.yml b/ansible/inventories/test/host_vars/custos/vars.yml
new file mode 100644
index 000000000..cbc60cc54
--- /dev/null
+++ b/ansible/inventories/test/host_vars/custos/vars.yml
@@ -0,0 +1,24 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+pkcs12_filename: 'custos-client-truststore.pkcs12'
+pkcs12_passphrase:
+nginx_site_config: site.conf.j2
\ No newline at end of file
diff --git a/ansible/inventories/test/host_vars/hashicorp/vars.yml b/ansible/inventories/test/host_vars/hashicorp/vars.yml
new file mode 100644
index 000000000..df45e25b3
--- /dev/null
+++ b/ansible/inventories/test/host_vars/hashicorp/vars.yml
@@ -0,0 +1,24 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+pkcs12_filename: 'vault-client-truststore.pkcs12'
+pkcs12_passphrase: "{{ hashicorp_pkcs12_passphrase }}"
+nginx_site_config: site.conf.j2
\ No newline at end of file
diff --git a/ansible/inventories/test/host_vars/keycloak/vars.yml b/ansible/inventories/test/host_vars/keycloak/vars.yml
new file mode 100644
index 000000000..30c06a724
--- /dev/null
+++ b/ansible/inventories/test/host_vars/keycloak/vars.yml
@@ -0,0 +1,24 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+pkcs12_filename: 'keycloak-client-truststore.pkcs12'
+pkcs12_passphrase: "{{ keycloak_pkcs12_passphrase }}"
+nginx_site_config: "{{ ansible_host }}.j2"
\ No newline at end of file
diff --git a/ansible/inventories/test/hosts.yml b/ansible/inventories/test/hosts.yml
new file mode 100644
index 000000000..97f7fb4f5
--- /dev/null
+++ b/ansible/inventories/test/hosts.yml
@@ -0,0 +1,44 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+all:
+  hosts:
+    custos:
+      ansible_host: bm-dev-1.usecustos.org
+      ansible_user: exouser
+      ansible_ssh_pass: "{{ custos_ssh_password }}"
+    keycloak:
+      ansible_host: bm-dev-2.usecustos.org
+      ansible_user: exouser
+      ansible_ssh_pass: "{{ keycloak_ssh_password }}"
+    hashicorp:
+      ansible_host: bm-dev-3.usecustos.org
+      ansible_user: exouser
+      ansible_ssh_pass: "{{ hashicorp_ssh_password }}"
+    old_custos:
+      ansible_host: dev.custos.usecustos.org
+      ansible_user: ubuntu
+    old_keycloak:
+      ansible_host: dev.keycloak.usecustos.org
+      ansible_user: ubuntu
+    old_hashicorp:
+      ansible_host: dev.vault.usecustos.org
+      ansible_user: ubuntu