Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- Sync upstream changes from master to develop #33

Merged
merged 5 commits into from
Jan 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .ansible-lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
exclude_paths:
- .*/
parseable: true
quiet: true
use_default_rules: true
verbosity: 1
skip_list:
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# ignore all retries files
*.retry
.idea/*

# ignore components symlink
roles/cpm
Expand Down
3 changes: 2 additions & 1 deletion .yamllint
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
ignore: |
.*/
tests/playbooks

rules:
braces:
Expand Down Expand Up @@ -54,4 +55,4 @@ rules:
new-lines:
type: unix
trailing-spaces: enable
truthy: disable
truthy: disable
179 changes: 179 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
pipeline {
agent {
node {
label 'ansible'
}
}
environment {
AWS_REGION = sh(script: 'curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | python -c "import json,sys;obj=json.load(sys.stdin);print obj[\'region\']"', returnStdout: true).trim()
// shortCommit = sh(script: "git log -n 1 --pretty=format:'%h'", returnStdout: true).trim()
CYBERARK_VERSION = "v11.1"
ENV_TIMESTAMP = sh(script: "date +%s", returnStdout: true).trim()
}
stages {
stage('Install virtual environment') {
steps {
sh '''
python -m pip install --user virtualenv
python -m virtualenv --no-site-packages .testenv
source .testenv/bin/activate
pip install -r requirements.txt
pip install -r tests/requirements.txt
'''
}
}
stage('yamllint validation') {
steps {
sh '''
source .testenv/bin/activate
yamllint .
'''
}
}
stage('Install ansible roles') {
steps {
sh '''
source .testenv/bin/activate
ansible-galaxy install -r requirements.yml
'''
}
}
stage('Download packages') {
steps {
withCredentials([
string(credentialsId: 'default_packages_bucket', variable: 'default_packages_bucket')
]) {
dir ('/tmp/packages') {
s3Download(file:'/tmp/packages/psm.zip', bucket:"$default_packages_bucket", path:"Packages/${env.CYBERARK_VERSION}/Privileged Session Manager-Rls-${env.CYBERARK_VERSION}.zip", pathStyleAccessEnabled: true, force:true)
s3Download(file:'/tmp/packages/cpm.zip', bucket:"$default_packages_bucket", path:"Packages/${env.CYBERARK_VERSION}/Central Policy Manager-Rls-${env.CYBERARK_VERSION}.zip", pathStyleAccessEnabled: true, force:true)
s3Download(file:'/tmp/packages/pvwa.zip', bucket:"$default_packages_bucket", path:"Packages/${env.CYBERARK_VERSION}/Password Vault Web Access-Rls-${env.CYBERARK_VERSION}.zip", pathStyleAccessEnabled: true, force:true)
}
}
}
}
stage('Deploy Vaults') {
parallel {
stage('Deploy Vault for in-domain environment') {
steps {
withCredentials([
usernamePassword(credentialsId: 'default_vault_credentials', passwordVariable: 'ansible_password', usernameVariable: 'ansible_user'),
string(credentialsId: 'default_keypair', variable: 'default_keypair'),
string(credentialsId: 'default_s3_bucket', variable: 'default_s3_bucket')
]) {
sh '''
source .testenv/bin/activate
ansible-playbook tests/playbooks/deploy_vault.yml -v -e "keypair=$default_keypair bucket=$default_s3_bucket ansible_user=$ansible_user ansible_password=$ansible_password domain=yes env_timestamp=$ENV_TIMESTAMP"
'''
}
}
}
stage('Deploy Vault for out-of-domain environment') {
steps {
sleep 10
withCredentials([
usernamePassword(credentialsId: 'default_vault_credentials', passwordVariable: 'ansible_password', usernameVariable: 'ansible_user'),
string(credentialsId: 'default_keypair', variable: 'default_keypair'),
string(credentialsId: 'default_s3_bucket', variable: 'default_s3_bucket')
]) {
sh '''
source .testenv/bin/activate
ansible-playbook tests/playbooks/deploy_vault.yml -v -e "keypair=$default_keypair bucket=$default_s3_bucket ansible_user=$ansible_user ansible_password=$ansible_password domain=no env_timestamp=$ENV_TIMESTAMP"
'''
}
}
}
}
}
stage('Provision testing environments') {
parallel {
stage('Provision in-domain testing environment') {
steps {
withCredentials([
usernamePassword(credentialsId: 'default_vault_credentials', passwordVariable: 'ansible_password', usernameVariable: 'ansible_user'),
string(credentialsId: 'default_keypair', variable: 'default_keypair')
]) {
sh '''
source .testenv/bin/activate
ansible-playbook tests/playbooks/pas-infrastructure/ec2-infrastructure.yml -e "aws_region=$AWS_REGION keypair=$default_keypair ec2_instance_type=m4.large public_ip=no pas_count=1 indomain=yes ansible_user=$ansible_user ansible_password=$ansible_password env_timestamp=$ENV_TIMESTAMP"
'''
}
}
}
stage('Provision out-of-domain testing environment') {
steps {
sleep 10
withCredentials([
usernamePassword(credentialsId: 'default_vault_credentials', passwordVariable: 'ansible_password', usernameVariable: 'ansible_user'),
string(credentialsId: 'default_keypair', variable: 'default_keypair')
]) {
sh '''
source .testenv/bin/activate
ansible-playbook tests/playbooks/pas-infrastructure/ec2-infrastructure.yml -e "aws_region=$AWS_REGION keypair=$default_keypair ec2_instance_type=m4.large public_ip=no pas_count=1 indomain=no ansible_user=$ansible_user ansible_password=$ansible_password env_timestamp=$ENV_TIMESTAMP"
'''
}
}
}
}
}
stage('Run pas-orchestrator') {
parallel {
stage('Run pas-orchestrator in-domain') {
steps {
withCredentials([usernamePassword(credentialsId: 'default_vault_credentials', passwordVariable: 'ansible_password', usernameVariable: 'ansible_user')]) {
sh '''
source .testenv/bin/activate
VAULT_IP=$(cat /tmp/vault_ip_domain_yes.txt)
cp -r tests/playbooks/pas-infrastructure/outputs/hosts_domain_yes.yml inventories/staging/hosts_domain_yes.yml
ansible-playbook pas-orchestrator.yml -i inventories/staging/hosts_domain_yes.yml -v -e "accept_eula=yes vault_ip=$VAULT_IP vault_password=$ansible_password cpm_zip_file_path=/tmp/packages/cpm.zip psm_zip_file_path=/tmp/packages/psm.zip pvwa_zip_file_path=/tmp/packages/pvwa.zip connect_with_rdp=yes ansible_user='cyberark.com\\\\$ansible_user' ansible_password=$ansible_password"
'''
}
}
}
stage('Run pas-orchestrator out-of-domain') {
steps {
withCredentials([usernamePassword(credentialsId: 'default_vault_credentials', passwordVariable: 'ansible_password', usernameVariable: 'ansible_user')]) {
sh '''
source .testenv/bin/activate
VAULT_IP=$(cat /tmp/vault_ip_domain_no.txt)
cp -r tests/playbooks/pas-infrastructure/outputs/hosts_domain_no.yml inventories/staging/hosts_domain_no.yml
ansible-playbook pas-orchestrator.yml -i inventories/staging/hosts_domain_no.yml -v -e "accept_eula=yes vault_ip=$VAULT_IP vault_password=$ansible_password {psm_out_of_domain:true} cpm_zip_file_path=/tmp/packages/cpm.zip psm_zip_file_path=/tmp/packages/psm.zip pvwa_zip_file_path=/tmp/packages/pvwa.zip connect_with_rdp=yes ansible_user='$ansible_user' ansible_password=$ansible_password"
'''
}
}
}
}
}
}
post('Archiving artifacts and Cleanup') {
always {
archiveArtifacts artifacts: 'logs/**/*.log', fingerprint: true
archiveArtifacts artifacts: 'logs/ansible.log', fingerprint: true
}
cleanup {
sh '''
source .testenv/bin/activate

# Terminate EC2 instances
instance_ids=$(aws ec2 describe-instances --region $AWS_REGION --query 'Reservations[].Instances[].InstanceId' --filters "Name=tag:Timestamp,Values=$ENV_TIMESTAMP" --output text)
aws ec2 terminate-instances --region $AWS_REGION --instance-ids $instance_ids
aws ec2 wait instance-terminated --region $AWS_REGION --instance-ids $instance_ids

instance_ids=$(aws ec2 describe-instances --region $AWS_REGION --query 'Reservations[].Instances[].InstanceId' --filters "Name=tag:aws:cloudformation:stack-name,Values=$(cat /tmp/cf_vault_domain_yes.txt)" --output text)
aws ec2 terminate-instances --region $AWS_REGION --instance-ids $instance_ids
aws ec2 wait instance-terminated --region $AWS_REGION --instance-ids $instance_ids

instance_ids=$(aws ec2 describe-instances --region $AWS_REGION --query 'Reservations[].Instances[].InstanceId' --filters "Name=tag:aws:cloudformation:stack-name,Values=$(cat /tmp/cf_vault_domain_no.txt)" --output text)
aws ec2 terminate-instances --region $AWS_REGION --instance-ids $instance_ids
aws ec2 wait instance-terminated --region $AWS_REGION --instance-ids $instance_ids

# Delete security groups
sleep 60
aws ec2 describe-security-groups --region $AWS_REGION --query 'SecurityGroups[*].{ID:GroupId}' --filters "Name=tag:Timestamp,Values=$ENV_TIMESTAMP" --output text | awk '{print $1}' | while read line; do aws ec2 delete-security-group --region $AWS_REGION --group-id $line; done

# Delete Vault Cloudformations
aws cloudformation delete-stack --region $AWS_REGION --stack-name $(cat /tmp/cf_vault_domain_yes.txt)
aws cloudformation delete-stack --region $AWS_REGION --stack-name $(cat /tmp/cf_vault_domain_no.txt)
'''
}
}
}
73 changes: 33 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# PAS-Orchestrator
# PAS-Orchestrator

In today’s modern infrastructure, organizations are moving towards hybrid environments, which consist of multiple public clouds, private clouds and on-premises platforms.
In today’s modern infrastructure, organizations are moving towards hybrid environments, which consist of multiple public clouds, private clouds and on-premises platforms.

CyberArk has created a tailored installation and deployment method for each platform to enable easy implementation. For example, CloudFormation templates enable easy deployment on AWS, while Azure Resource Manager (ARM) templates enable easy deployment on Azure. However, it is difficult to combine the different methods to orchestrate and automate a hybrid deployment.

PAS Orchestrator is a set of Ansible roles which provides a holistic solution to deploying CyberArk Core PAS components simultaneously in multiple environments, regardless of the environment’s location.
PAS Orchestrator is a set of Ansible roles which provides a holistic solution to deploying CyberArk Core PAS components simultaneously in multiple environments, regardless of the environment’s location.

The Ansible roles are responsible for the entire deployment process, and can be integrated with the organization’s CI/CD pipeline.
The Ansible roles are responsible for the entire deployment process, and can be integrated with the organization’s CI/CD pipeline.

Each PAS component’s Ansible role is responsible for the component end-2-end deployment, which includes the following stages for each component:
Each PAS component’s Ansible role is responsible for the component end-2-end deployment, which includes the following stages for each component:
- Copy the installation package to the target server
- Installing prerequisites
- Silent installation of the component
Expand All @@ -20,41 +20,38 @@ Ansible Roles for PVWA, CPM and PSM can be found in the following links:
- CPM: [https://github.com/cyberark/cpm](https://github.com/cyberark/cpm)
- PVWA: [https://github.com/cyberark/pvwa](https://github.com/cyberark/pvwa)

The PAS Orchestrator role is an example of how to use the component roles
demonstrating paralel installation on multiple remote servers
The PAS Orchestrator role is an example of how to use the component roles
demonstrating paralel installation on multiple remote servers

## Requirements
------------
## Requirements

- IP addresses / hosts to execute the playbook against with Windows 2016 installed on the remote hosts
- WinRM open on port 5986 (**not 5985**) on the remote host
- WinRM open on port 5986 (**not 5985**) on the remote host
- Pywinrm is installed on the workstation running the playbook
- The workstation running the playbook must have network connectivity to the remote host
- The remote host must have Network connectivity to the CyberArk vault and the repository server
- 443 port outbound
- 443 port outbound (for PVWA only)
- 1858 port outbound
- Administrator access to the remote host
- CyberArk components CD image on the workstation running the playbook

## Environment setup
------------
- Get the PAS Orchestrator Role
```
git clone https://github.com/cyberark/pas-orchestrator.git
```
- Install Ansible
```
pip install ansible pywinrm pywinrm[credssp] requests-credssp --user
- 1858 port outbound
- Administrator access to the remote host
- CyberArk components CD image on the workstation running the playbook

## Environment setup

- Get the PAS Orchestrator Playbook
```
- Get the components roles
```
git clone https://github.com/cyberark/pas-orchestrator.git
cd pas-orchestrator
```
- Install Python requirements
```
pip install -r requirements.txt
```
- Get the components roles
```
ansible-galaxy install --roles-path ./roles --role-file requirements.yml
```
- Update the inventories hosts file with the remote hosts IPs


- Update the inventories hosts file with the remote hosts IPs

## Role Variables

Expand All @@ -74,7 +71,6 @@ These are the variables used in this playbook
| pvwa_zip_file_path | yes | None | Path to zipped PVWA image |
| psm_zip_file_path | yes | None | Path to zipped PSM image |


Variables related to the components can be found on the Components README

## Usage
Expand Down Expand Up @@ -134,32 +130,29 @@ Prior to running pas-orchestrator hosts file should be "updated" [https://github
cpm
psm


## Running the playbook:

To run the above playbook, execute the following command example :

ansible-playbook -i ./inventories/production pas-orchestrator.yml -e "vault_ip=VAULT_IP ansible_user=DOMAIN\USER cpm_zip_file_path=/tmp/pas_packages/cpm.zip pvwa_zip_file_path=/tmp/pas_packages/pvwa.zip psm_zip_file_path=/tmp/pas_packages/psm.zip connect_with_rdp=Yes accept_eula=Yes"



Command example for out of Domain , no hardening deployment in drive D:

ansible-playbook -i ./inventories/production pas-orchestrator.yml -e "vault_ip=VAULT_IP ansible_user=DOMAIN\USER cpm_zip_file_path=/tmp/pas_packages/cpm.zip pvwa_zip_file_path=/tmp/pas_packages/pvwa.zip psm_zip_file_path=/tmp/pas_packages/psm.zip {psm_out_of_domain:true} connect_with_rdp=Yes accept_eula=Yes psm_installation_drive=D: cpm_installation_drive=D: pvwa_installation_drive=D: {psm_hardening:false} {cpm_hardening:false} {pvwa_hardening:false}"


** *Vault and remote host passwords are entered via Prompt*
** *Vault and remote host passwords are entered via Prompt*

## Troubleshooting
In case of a failure, a Log folder with be created on the Ansible workstation with the relevant logs copied from the remote host machine.
The logs are available under - pas-orchestrator/tasks/logs

In case of a failure, a Log folder with be created on the Ansible workstation with the relevant logs copied from the remote host machine.
The logs are available under - pas-orchestrator/tasks/logs

## Idempotence
Every stage in the roles contains validation and can be run multiple times without error.
Every stage in the roles contains validation and can be run multiple times without error.

## Limitations
- Only single component per server is supported
- There is a check sum verification to the CD image zip file , it must be the original cyberArk release
## Limitations
- Only single component per server is supported
- There is a check sum verification to the CD image zip file , it must be the original CyberArk release

## License

Expand Down
4 changes: 2 additions & 2 deletions ansible.cfg
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[defaults]

# Default path to roles directory
roles_path = ./roles
roles_path = ./roles

# Adds timestamp to each task and add a recap on the end of the playbook
callback_whitelist = profile_tasks
log_path=tasks/logs/ansible.log
log_path = ./logs/ansible.log
; host_key_checking = False
File renamed without changes.
30 changes: 30 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
ansible==2.8.6
boto==2.49.0
boto3==1.10.5
botocore==1.13.5
certifi==2019.9.11
cffi==1.13.1
chardet==3.0.4
cryptography==2.8
docutils==0.15.2
enum34==1.1.6
futures==3.3.0
idna==2.8
ipaddress==1.0.23
Jinja2==2.10.3
jmespath==0.9.4
MarkupSafe==1.1.1
ntlm-auth==1.4.0
pyasn1==0.4.7
pycparser==2.19
pyOpenSSL==19.0.0
python-dateutil==2.8.0
pywinrm==0.3.0
PyYAML==5.1.2
requests==2.22.0
requests-credssp==1.1.0
requests-ntlm==1.1.0
s3transfer==0.2.1
six==1.12.0
urllib3==1.25.6
xmltodict==0.12.0
Loading