diff --git a/ansible/roles/release/files/upload_release.py b/ansible/roles/release/files/upload_release.py new file mode 100644 index 0000000..548298b --- /dev/null +++ b/ansible/roles/release/files/upload_release.py @@ -0,0 +1,64 @@ +#!/usr/bin/python +import argparse +import glob +import os + +from github import Github +''' +upload_release.py - Uploads one or more files to a specified release for a Github repository + +Author: Jordan Wright +''' + + +def main(): + parser = argparse.ArgumentParser( + description='Upload assets to a given repository release') + parser.add_argument('--repo', help='The repository to upload the asset to') + parser.add_argument('--version', help='The version of the release') + parser.add_argument( + '--assets', + help='The files to upload to the Github release', + nargs='+') + args = parser.parse_args() + + try: + API_KEY = os.environ['GITHUB_API_KEY'] + except KeyError as e: + print os.environ + print('Error: Missing GITHUB_API_KEY environment variable') + return + + g = Github(API_KEY) + + # Verify the repo exists + try: + repo = g.get_repo(args.repo, lazy=False) + except Exception as e: + print('Error getting repo {}: {}'.format(args.repo, e)) + return + + # Verify the release exists + try: + release = None + for r in repo.get_releases(): + if r.tag_name == args.version: + release = r + break + if not release: + print('Release {} not found'.format(args.version)) + return + except Exception as e: + print('Error getting release {}: {}'.format(args.version, e)) + return + + for asset in args.assets: + try: + release.upload_asset(asset) + print('Uploaded {} to release {}'.format(asset, args.version)) + except Exception as e: + print('Error uploading asset {}: {}'.format(asset, e)) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/ansible/roles/release/tasks/main.yml b/ansible/roles/release/tasks/main.yml new file mode 100644 index 0000000..ce41799 --- /dev/null +++ b/ansible/roles/release/tasks/main.yml @@ -0,0 +1,276 @@ +- name: update packages + apt: + update_cache: yes + upgrade: yes + +- name: add https apt transport for Docker repository + apt: + name: apt-transport-https + state: present + +- name: install docker key + apt_key: + id: "{{ apt_docker_fingerprint }}" + url: "{{ apt_docker_keyserver }}" + +- name: add docker repository + apt_repository: + repo: "{{ apt_docker_repo }}" + mode: '644' + update_cache: yes + state: present + +- name: install docker repository + apt: + name: "docker-ce" + state: present + +- name: install git + apt: + name: git + state: present + +- name: install python/pip + apt: + name: python-pip + state: present + +- name: install pygithub + command: "pip install git+https://github.com/PyGithub/PyGithub.git@master" + +- name: download golang + get_url: + url: "{{ go_download_location }}" + dest: /usr/local/src/{{ go_tarball }} + checksum: "sha256:{{ go_tarball_checksum }}" + +- name: extract golang tarball + unarchive: + src: /usr/local/src/{{ go_tarball }} + dest: /usr/local + copy: no + +- name: install docker module + pip: + name: docker + +- name: download the xgo docker image + docker_image: + name: "{{ xgo_image }}" + +- name: clone the xgo helper + shell: "/usr/local/go/bin/go get {{ xgo_golang_package }}" + +- name: clone the gophish repo + shell: "/usr/local/go/bin/go get {{ gophish_golang_package }}" + +- name: build gophish + docker_container: + name: "gophish_build" + image: "{{ xgo_image }}" + auto_remove: true + volumes: + - "{{ gophish_directory }}/bin:/build" + - "/root/.xgo-cache:/deps-cache:ro" + env: + TARGETS: "linux/386 linux/amd64 windows/386 windows/amd64 darwin/386 darwin/amd64" + command: "github.com/gophish/gophish" + +- name: wait for linux 32-bit build + wait_for: + path: "{{ gophish_directory }}/bin/gophish-linux-386" + +- name: wait for linux 64-bit build + wait_for: + path: "{{ gophish_directory }}/bin/gophish-linux-amd64" + +- name: wait for the windows 32-bit build + wait_for: + path: "{{ gophish_directory }}/bin/gophish-windows-4.0-386.exe" + +- name: wait for the windows 64-bit build + wait_for: + path: "{{ gophish_directory }}/bin/gophish-windows-4.0-amd64.exe" + +- name: wait for the osx 32-bit build + wait_for: + path: "{{ gophish_directory }}/bin/gophish-darwin-10.6-386" + +- name: wait for the osx 64-bit build + wait_for: + path: "{{ gophish_directory }}/bin/gophish-darwin-10.6-amd64" + +- name: packaging linux-32 bit release + block: + - command: "cp {{ gophish_directory }}/bin/gophish-linux-386 {{ gophish_directory }}/gophish" + args: + creates: "{{ gophish_directory }}/gophish" + - archive: + path: + - "{{ gophish_directory }}/static/js/dist" + - "{{ gophish_directory }}/static/js/src/vendor/ckeditor" + - "{{ gophish_directory }}/static/css/dist" + - "{{ gophish_directory }}/static/images" + - "{{ gophish_directory }}/static/font" + - "{{ gophish_directory }}/static/db" + - "{{ gophish_directory }}/db" + - "{{ gophish_directory }}/templates" + - "{{ gophish_directory }}/README.md" + - "{{ gophish_directory }}/VERSION" + - "{{ gophish_directory }}/LICENSE" + - "{{ gophish_directory }}/config.json" + - "{{ gophish_directory }}/gophish" + dest: "{{ gophish_linux_32bit }}" + format: zip + - file: + path: "{{ gophish_directory }}/gophish" + state: absent + +- name: packaging linux-64 bit release + block: + - command: "cp {{ gophish_directory }}/bin/gophish-linux-amd64 {{ gophish_directory }}/gophish" + args: + creates: "{{ gophish_directory }}/gophish" + - archive: + path: + - "{{ gophish_directory }}/static/js/dist" + - "{{ gophish_directory }}/static/js/src/vendor/ckeditor" + - "{{ gophish_directory }}/static/css/dist" + - "{{ gophish_directory }}/static/images" + - "{{ gophish_directory }}/static/font" + - "{{ gophish_directory }}/static/db" + - "{{ gophish_directory }}/db" + - "{{ gophish_directory }}/templates" + - "{{ gophish_directory }}/README.md" + - "{{ gophish_directory }}/VERSION" + - "{{ gophish_directory }}/LICENSE" + - "{{ gophish_directory }}/config.json" + - "{{ gophish_directory }}/gophish" + dest: "{{ gophish_linux_64bit }}" + format: zip + - file: + path: "{{ gophish_directory }}/gophish" + state: absent + +- name: packaging windows 32-bit release + block: + - command: "cp {{ gophish_directory }}/bin/gophish-windows-4.0-386.exe {{ gophish_directory }}/gophish.exe" + args: + creates: "{{ gophish_directory }}/gophish.exe" + - archive: + path: + - "{{ gophish_directory }}/static/js/dist" + - "{{ gophish_directory }}/static/js/src/vendor/ckeditor" + - "{{ gophish_directory }}/static/css/dist" + - "{{ gophish_directory }}/static/images" + - "{{ gophish_directory }}/static/font" + - "{{ gophish_directory }}/static/db" + - "{{ gophish_directory }}/db" + - "{{ gophish_directory }}/templates" + - "{{ gophish_directory }}/README.md" + - "{{ gophish_directory }}/VERSION" + - "{{ gophish_directory }}/LICENSE" + - "{{ gophish_directory }}/config.json" + - "{{ gophish_directory }}/gophish.exe" + dest: "{{ gophish_windows_32bit }}" + format: zip + - file: + path: "{{ gophish_directory }}/gophish.exe" + state: absent + +- name: packaging windows 64-bit release + block: + - command: "cp {{ gophish_directory }}/bin/gophish-windows-4.0-amd64.exe {{ gophish_directory }}/gophish.exe" + args: + creates: "{{ gophish_directory }}/gophish.exe" + - archive: + path: + - "{{ gophish_directory }}/static/js/dist" + - "{{ gophish_directory }}/static/js/src/vendor/ckeditor" + - "{{ gophish_directory }}/static/css/dist" + - "{{ gophish_directory }}/static/images" + - "{{ gophish_directory }}/static/font" + - "{{ gophish_directory }}/static/db" + - "{{ gophish_directory }}/db" + - "{{ gophish_directory }}/templates" + - "{{ gophish_directory }}/README.md" + - "{{ gophish_directory }}/VERSION" + - "{{ gophish_directory }}/LICENSE" + - "{{ gophish_directory }}/config.json" + - "{{ gophish_directory }}/gophish.exe" + dest: "{{ gophish_windows_64bit }}" + format: zip + - file: + path: "{{ gophish_directory }}/gophish.exe" + state: absent + +- name: packaging osx 32-bit release + block: + - command: "cp {{ gophish_directory }}/bin/gophish-darwin-10.6-386 {{ gophish_directory }}/gophish" + args: + creates: "{{ gophish_directory }}/gophish" + - archive: + path: + - "{{ gophish_directory }}/static/js/dist" + - "{{ gophish_directory }}/static/js/src/vendor/ckeditor" + - "{{ gophish_directory }}/static/css/dist" + - "{{ gophish_directory }}/static/images" + - "{{ gophish_directory }}/static/font" + - "{{ gophish_directory }}/static/db" + - "{{ gophish_directory }}/db" + - "{{ gophish_directory }}/templates" + - "{{ gophish_directory }}/README.md" + - "{{ gophish_directory }}/VERSION" + - "{{ gophish_directory }}/LICENSE" + - "{{ gophish_directory }}/config.json" + - "{{ gophish_directory }}/gophish" + dest: "{{ gophish_osx_32bit }}" + format: zip + - file: + path: "{{ gophish_directory }}/gophish" + state: absent + +- name: packaging osx 64-bit release + block: + - command: "cp {{ gophish_directory }}/bin/gophish-darwin-10.6-amd64 {{ gophish_directory }}/gophish" + args: + creates: "{{ gophish_directory }}/gophish" + - archive: + path: + - "{{ gophish_directory }}/static/js/dist" + - "{{ gophish_directory }}/static/js/src/vendor/ckeditor" + - "{{ gophish_directory }}/static/css/dist" + - "{{ gophish_directory }}/static/images" + - "{{ gophish_directory }}/static/font" + - "{{ gophish_directory }}/static/db" + - "{{ gophish_directory }}/db" + - "{{ gophish_directory }}/templates" + - "{{ gophish_directory }}/README.md" + - "{{ gophish_directory }}/VERSION" + - "{{ gophish_directory }}/LICENSE" + - "{{ gophish_directory }}/config.json" + - "{{ gophish_directory }}/gophish" + dest: "{{ gophish_osx_64bit }}" + format: zip + - file: + path: "{{ gophish_directory }}/gophish" + state: absent + +- name: copy upload release script + copy: + src: "{{role_path}}/files/upload_release.py" + dest: "{{upload_release}}" + mode: 0700 + +- name: upload assets to github release + shell: > + {{upload_release}} --repo gophish/gophish --version {{ version }} + --assets {{ gophish_windows_32bit }} {{ gophish_windows_64bit }} + {{ gophish_linux_32bit }} {{ gophish_linux_64bit }} + {{ gophish_osx_32bit}} {{ gophish_osx_64bit }} + environment: + GITHUB_API_KEY: "{{github_token}}" + register: + upload + +- debug: msg="{{ upload.stdout }}" \ No newline at end of file diff --git a/ansible/roles/release/vars/main.yml b/ansible/roles/release/vars/main.yml new file mode 100644 index 0000000..bce8d8a --- /dev/null +++ b/ansible/roles/release/vars/main.yml @@ -0,0 +1,25 @@ +apt_docker_dist: "https://download.docker.com/linux/{{ ansible_distribution|lower }}" +apt_docker_repo: "deb [arch=amd64] {{ apt_docker_dist }} {{ ansible_distribution_release|lower }} stable" +apt_docker_keyserver: "{{ apt_docker_dist }}/gpg" +apt_docker_fingerprint: "9DC858229FC7DD38854AE2D88D81803C0EBFCD88" + +gophish_golang_package: "github.com/gophish/gophish" +gophish_directory: "/root/go/src/{{ gophish_golang_package }}" +gophish_windows_32bit: "{{gophish_directory}}/bin/gophish-{{version}}-windows-32bit.zip" +gophish_windows_64bit: "{{gophish_directory}}/bin/gophish-{{version}}-windows-64bit.zip" +gophish_linux_32bit: "{{gophish_directory}}/bin/gophish-{{version}}-linux-32bit.zip" +gophish_linux_64bit: "{{gophish_directory}}/bin/gophish-{{version}}-linux-64bit.zip" +gophish_osx_32bit: "{{gophish_directory}}/bin/gophish-{{version}}-osx-32bit.zip" +gophish_osx_64bit: "{{gophish_directory}}/bin/gophish-{{version}}-osx-64bit.zip" + +xgo_image: "karalabe/xgo-latest" +xgo_golang_package: "github.com/karalabe/xgo" + +go_tarball: "go1.9.2.linux-amd64.tar.gz" +go_download_location: "https://dl.google.com/go/{{go_tarball}}" +go_tarball_checksum: "de874549d9a8d8d8062be05808509c09a88a248e77ec14eb77453530829ac02b" + +github_token: !vault | + $ANSIBLE_VAULT;[redacted] + +upload_release: "/usr/local/bin/upload_release.py" \ No newline at end of file diff --git a/ansible/site.yml b/ansible/site.yml new file mode 100644 index 0000000..b9f8e38 --- /dev/null +++ b/ansible/site.yml @@ -0,0 +1,77 @@ +--- +- hosts: localhost + connection: local + + vars: + vault_do_token: !vault | + $ANSIBLE_VAULT;redacted + + tasks: + - name: ensure ssh key exists + user: + name: "{{ ansible_user_id }}" + generate_ssh_key: yes + ssh_key_file: .ssh/gophish_dev + ssh_key_bits: 4096 + + - name: ensure ssh key is uploaded to DigitalOcean + digital_ocean: + state: present + command: ssh + name: gophish-dev + ssh_pub_key: "{{ lookup('file', '~/.ssh/gophish_dev.pub') }}" + api_token: "{{ vault_do_token }}" + register: gophish_ssh_key + + - name: create the droplet used to build releases + digital_ocean: + state: present + command: droplet + name: gophish-release + api_token: "{{ vault_do_token }}" + size_id: s-1vcpu-1gb + region_id: nyc1 + image_id: debian-9-x64 + wait_timeout: 500 + ssh_key_ids: "{{ gophish_ssh_key.ssh_key.id }}" + unique_name: yes + register: gophish_droplet + + - debug: + msg: "ID is {{ gophish_droplet.droplet.id }}" + + - debug: + msg: "IP is {{ gophish_droplet.droplet.ip_address }}" + + - name: add the droplet to our inventory + add_host: + name: "{{ gophish_droplet.droplet.ip_address }}" + groups: droplets + ansible_ssh_private_key_file: ~/.ssh/gophish_dev + + - name: wait for port 22 to become available. + local_action: wait_for host="{{ gophish_droplet.droplet.ip_address }}" port=22 delay=5 timeout=600 + +- hosts: droplets + remote_user: root + roles: + - release + + environment: + PATH: "{{ ansible_env.path }}:/usr/local/go/bin" + +- hosts: localhost + connection: local + + vars: + vault_do_token: !vault | + $ANSIBLE_VAULT;redacted + + tasks: + - name: remove the droplet + digital_ocean: + state: absent + command: droplet + name: gophish-release + api_token: "{{ vault_do_token }}" + wait_timeout: 500 \ No newline at end of file