├── ansible-modules
├── README.md
├── ansible.cfg
├── examples_common_modules.yml
├── hosts
├── library
│ └── epoch_converter.py
└── test_custom_module.yml
├── ansible-roles
├── README.md
├── Vagrantfile
├── ansible.cfg
├── hosts
├── main_playbook.yml
└── roles
│ ├── test_role
│ ├── .travis.yml
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ ├── tests
│ │ ├── inventory
│ │ └── test.yml
│ └── vars
│ │ └── main.yml
│ └── webserver
│ ├── README.md
│ ├── defaults
│ └── main.yml
│ ├── files
│ └── index.html
│ ├── handlers
│ └── main.yml
│ ├── meta
│ └── main.yml
│ ├── tasks
│ └── main.yml
│ ├── templates
│ └── nginx.conf.j2
│ └── vars
│ └── main.yml
├── ansible-variables
├── .gitignore
├── README.md
├── Vagrantfile
├── ansible.cfg
├── example-anchors-aliases.yml
├── example-external-vars.yml
├── example-register-variable-conditionals.yml
├── example-register-variable.yml
├── example-simple-variable.yml
├── example-variable-types.yml
├── group_vars
│ ├── all
│ └── webservers
├── host_vars
│ ├── host1
│ └── host2
├── hosts
├── roles
│ └── common
│ │ ├── defaults
│ │ └── main.yml
│ │ └── vars
│ │ └── main.yml
└── vars
│ └── variables.yml
├── az-ad-group-module
├── ad_group
│ ├── main.tf
│ └── variables.tf
├── azure-pipeline.yaml
├── main.tf
├── terraform.tfvars
└── variables.tf
├── cdktf-aws-python-webserver
├── .gitignore
├── Pipfile
├── Pipfile.lock
├── README.md
├── cdktf.json
├── help
├── main-test.py
└── main.py
├── eks-blueprints-terraform
├── README.md
├── dev_teams.tf
├── eks_blueprints_addons.tf
├── initial_skeleton
│ ├── main.tf
│ ├── variables.tf
│ └── versions.tf
├── karpenter.tf
├── main.tf
├── outputs.tf
├── platform_team.tf
├── variables.tf
└── versions.tf
├── iac-examples
├── README.MD
├── storage.bicep
├── storage.json
├── storage.tf
└── storage_pulumi.py
├── terraform-best-practices
├── README.md
├── separate-environments-project-structure
│ ├── environment
│ │ ├── production
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ ├── terraform.tfvars
│ │ │ └── variables.tf
│ │ ├── staging
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ ├── terraform.tfvars
│ │ │ └── variables.tf
│ │ └── test
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ ├── terraform.tfvars
│ │ │ └── variables.tf
│ └── modules
│ │ └── vpc
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── varariables.tf
└── small-terraform-project-structure
│ ├── README.md
│ ├── main.tf
│ ├── outputs.tf
│ ├── terraform.tfvars
│ └── variables.tf
├── terraform-github-actions
├── .github
│ └── workflows
│ │ └── terraform.yml
├── README.md
└── terraform
│ └── main.tf
├── terraform-output
├── README.md
├── main.tf
├── modules
│ ├── aws-web-server-instance
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── aws-web-server-vpc
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
├── outputs.tf
├── terraform.tfvars
└── variables.tf
├── terraform-tfvars
├── dev.auto.tfvars
├── main.tf
├── modules
│ ├── main.tf
│ ├── terraform.tfvars
│ └── variable.tf
├── prod.tfvars
└── variable.tf
└── working-with-ansible-playbooks
├── README.md
├── Vagrantfile
├── ansible.cfg
├── example-conditionals-playbook.yml
├── example-handlers-playbook.yml
├── example-loops-playbook.yml
├── example-secrets-playbook.yml
├── example-simple-playbook.yml
├── example-variables-2-playbook.yml
├── example-variables-playbook.yml
├── example_file
└── hosts
/ansible-modules/README.md:
--------------------------------------------------------------------------------
1 | This repository includes content related to the [Ansible Modules]() demo on Spacelift blog.
--------------------------------------------------------------------------------
/ansible-modules/ansible.cfg:
--------------------------------------------------------------------------------
1 | [defaults]
2 | inventory=./hosts
3 | deprecation_warnings=False
4 | nocows = 1
5 | duplicate_dict_key=ignore
6 | action_warnings=False
--------------------------------------------------------------------------------
/ansible-modules/examples_common_modules.yml:
--------------------------------------------------------------------------------
1 | - name: Examples Common Modules
2 | hosts: all
3 | vars:
4 | nginx_version: 1.18.0-0ubuntu1.3
5 |
6 | tasks:
7 | - name: "Install Nginx to version {{ nginx_version }} with apt module"
8 | ansible.builtin.apt:
9 | name: "nginx={{ nginx_version }}"
10 | state: present
11 |
12 | - name: Update the repository cache and update package "nginx" to latest version
13 | ansible.builtin.apt:
14 | name: nginx
15 | state: latest
16 | update_cache: yes
17 |
18 | - name: Update the repository cache and update package "nginx" to latest version
19 | ansible.builtin.yum:
20 | name: nginx
21 | state: latest
22 | update_cache: yes
23 |
24 | - name: Restart docker service
25 | ansible.builtin.service:
26 | name: docker
27 | state: restarted
28 |
29 | - name: Create the directory "/etc/test" if it doesnt exist and set permissions
30 | ansible.builtin.file:
31 | path: /etc/test
32 | state: directory
33 | mode: '0750'
34 |
35 | - name: Copy file with owner and permissions
36 | ansible.builtin.copy:
37 | src: /example_directory/test
38 | dest: /target_directory/test
39 | owner: joe
40 | group: admins
41 | mode: '0755'
42 |
43 | - name: Copy and template the Nginx configuration file to the host
44 | ansible.builtin.template:
45 | src: templates/nginx.conf.j2
46 | dest: /etc/nginx/sites-available/default
47 |
48 | - name: Add a line to a file if it doesnt exist
49 | ansible.builtin.lineinfile:
50 | path: /tmp/example_file
51 | line: "This line must exist in the file"
52 | state: present
53 |
54 | - name: Add a block of configuration options at the end of the file if it doesnt exist
55 | ansible.builtin.blockinfile:
56 | path: /etc/example_dictory/example.conf
57 | block: |
58 | feature1_enabled: true
59 | feature2_enabled: false
60 | feature2_enabled: true
61 | insertafter: EOF
62 |
63 | - name: Run daily DB backup script at 00:00
64 | ansible.builtin.cron:
65 | name: "Run daily DB backup script at 00:00"
66 | minute: "0"
67 | hour: "0"
68 | job: "/usr/local/bin/db_backup_script.sh > /var/log/db_backup_script.sh.log 2>&1"
69 |
70 | - name: Wait until a string is in the file before continuing
71 | ansible.builtin.wait_for:
72 | path: /tmp/example_file
73 | search_regex: "String exists, continue"
74 |
75 | - name: Execute a script in remote shell and capture the output to file
76 | ansible.builtin.shell: script.sh >> script_output.log
77 |
78 | - name: Install Docker dependencies
79 | ansible.builtin.apt:
80 | name:
81 | - curl
82 | - ca-certificates
83 | - gnupg2
84 | - lsb-release
85 | state: latest
--------------------------------------------------------------------------------
/ansible-modules/hosts:
--------------------------------------------------------------------------------
1 | [testgroup]
2 | host1 ansible_host=127.0.0.1
--------------------------------------------------------------------------------
/ansible-modules/library/epoch_converter.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | from __future__ import (absolute_import, division, print_function)
4 | __metaclass__ = type
5 | import datetime
6 |
7 | DOCUMENTATION = r'''
8 | ---
9 | module: epoch_converter
10 |
11 | short_description: This module converts an epoch timestamp to human-readable date.
12 |
13 | # If this is part of a collection, you need to use semantic versioning,
14 | # i.e. the version is of the form "2.5.0" and not "2.4".
15 | version_added: "1.0.0"
16 |
17 | description: This modules takes a string that represents a Unix epoch timestamp and displays its human-readable date equivalent.
18 |
19 | options:
20 | epoch_timestamp:
21 | description: This is the string that represents a Unix epoch timestamp.
22 | required: true
23 | type: str
24 | state_changed:
25 | description: This string simulates a modification of the target's state.
26 | required: false
27 | type: bool
28 |
29 | author:
30 | - Ioannis Moustakis (@Imoustak)
31 | '''
32 |
33 | EXAMPLES = r'''
34 | # Convert an epoch timestamp
35 | - name: Convert an epoch timestamp
36 | epoch_converter:
37 | epoch_timestamp: 1657382362
38 | '''
39 |
40 | RETURN = r'''
41 | # These are examples of possible return values, and in general should use other names for return values.
42 | human_readable_date:
43 | description: The human-readable equivalent of the epoch timestamp input.
44 | type: str
45 | returned: always
46 | sample: '2022-07-09T17:59:22'
47 | original_timestamp:
48 | description: The original epoch timestamp input.
49 | type: str
50 | returned: always
51 | sample: '16573823622'
52 |
53 | '''
54 |
55 | from ansible.module_utils.basic import AnsibleModule
56 |
57 |
58 | def run_module():
59 | # define available arguments/parameters a user can pass to the module
60 | module_args = dict(
61 | epoch_timestamp=dict(type='str', required=True),
62 | state_changed=dict(type='bool', required=False)
63 | )
64 |
65 | # seed the result dict in the object
66 | # we primarily care about changed and state
67 | # changed is if this module effectively modified the target
68 | # state will include any data that you want your module to pass back
69 | # for consumption, for example, in a subsequent task
70 | result = dict(
71 | changed=False,
72 | human_readable_date='',
73 | original_timestamp=''
74 | )
75 |
76 | # the AnsibleModule object will be our abstraction working with Ansible
77 | # this includes instantiation, a couple of common attr would be the
78 | # args/params passed to the execution, as well as if the module
79 | # supports check mode
80 | module = AnsibleModule(
81 | argument_spec=module_args,
82 | supports_check_mode=True
83 | )
84 |
85 | # if the user is working with this module in only check mode we do not
86 | # want to make any changes to the environment, just return the current
87 | # state with no modifications
88 | if module.check_mode:
89 | module.exit_json(**result)
90 |
91 | # manipulate or modify the state as needed (this is going to be the
92 | # part where your module will do what it needs to do)
93 | result['original_timestamp'] = module.params['epoch_timestamp']
94 | result['human_readable_date'] = datetime.datetime.fromtimestamp(int(module.params['epoch_timestamp']))
95 |
96 | # use whatever logic you need to determine whether or not this module
97 | # made any modifications to your target
98 | if module.params['state_changed']:
99 | result['changed'] = True
100 |
101 | # during the execution of the module, if there is an exception or a
102 | # conditional state that effectively causes a failure, run
103 | # AnsibleModule.fail_json() to pass in the message and the result
104 | if module.params['epoch_timestamp'] == 'fail':
105 | module.fail_json(msg='You requested this to fail', **result)
106 |
107 | # in the event of a successful module execution, you will want to
108 | # simple AnsibleModule.exit_json(), passing the key/value results
109 | module.exit_json(**result)
110 |
111 |
112 | def main():
113 | run_module()
114 |
115 |
116 | if __name__ == '__main__':
117 | main()
118 |
--------------------------------------------------------------------------------
/ansible-modules/test_custom_module.yml:
--------------------------------------------------------------------------------
1 | - name: Test my new module
2 | hosts: localhost
3 | tasks:
4 | - name: Run the new module
5 | epoch_converter:
6 | epoch_timestamp: '1657382362'
7 | state_changed: yes
8 | register: show_output
9 | - name: Show Output
10 | debug:
11 | msg: '{{ show_output }}'
--------------------------------------------------------------------------------
/ansible-roles/README.md:
--------------------------------------------------------------------------------
1 | This repository includes content related to the [Ansible Roles](https://spacelift.io/blog/ansible-roles) demo on Spacelift blog.
--------------------------------------------------------------------------------
/ansible-roles/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure
5 | # configures the configuration version (we support older styles for
6 | # backwards compatibility). Please don't change it unless you know what
7 | # you're doing.
8 | Vagrant.configure("2") do |config|
9 | # The most common configuration options are documented and commented below.
10 | # For a complete reference, please see the online documentation at
11 | # https://docs.vagrantup.com.
12 |
13 | # Every Vagrant development environment requires a box. You can search for
14 | # boxes at https://vagrantcloud.com/search.
15 |
16 | config.vm.define "host1" do |host1|
17 | host1.vm.box = "ubuntu/focal64"
18 | end
19 |
20 |
21 | # Disable automatic box update checking. If you disable this, then
22 | # boxes will only be checked for updates when the user runs
23 | # `vagrant box outdated`. This is not recommended.
24 | # config.vm.box_check_update = false
25 |
26 | # Create a forwarded port mapping which allows access to a specific port
27 | # within the machine from a port on the host machine. In the example below,
28 | # accessing "localhost:8080" will access port 80 on the guest machine.
29 | # NOTE: This will enable public access to the opened port
30 | # config.vm.network "forwarded_port", guest: 80, host: 8080
31 |
32 | # Create a forwarded port mapping which allows access to a specific port
33 | # within the machine from a port on the host machine and only allow access
34 | # via 127.0.0.1 to disable public access
35 | # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
36 |
37 | # Create a private network, which allows host-only access to the machine
38 | # using a specific IP.
39 | # config.vm.network "private_network", ip: "192.168.33.10"
40 |
41 | # Create a public network, which generally matched to bridged network.
42 | # Bridged networks make the machine appear as another physical device on
43 | # your network.
44 | # config.vm.network "public_network"
45 |
46 | # Share an additional folder to the guest VM. The first argument is
47 | # the path on the host to the actual folder. The second argument is
48 | # the path on the guest to mount the folder. And the optional third
49 | # argument is a set of non-required options.
50 | # config.vm.synced_folder "../data", "/vagrant_data"
51 |
52 | # Provider-specific configuration so you can fine-tune various
53 | # backing providers for Vagrant. These expose provider-specific options.
54 | # Example for VirtualBox:
55 | #
56 | # config.vm.provider "virtualbox" do |vb|
57 | # # Display the VirtualBox GUI when booting the machine
58 | # vb.gui = true
59 | #
60 | # # Customize the amount of memory on the VM:
61 | # vb.memory = "1024"
62 | # end
63 | #
64 | # View the documentation for the provider you are using for more
65 | # information on available options.
66 |
67 | # Enable provisioning with a shell script. Additional provisioners such as
68 | # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
69 | # documentation for more information about their specific syntax and use.
70 | # config.vm.provision "shell", inline: <<-SHELL
71 | # apt-get update
72 | # apt-get install -y apache2
73 | # SHELL
74 | end
75 |
--------------------------------------------------------------------------------
/ansible-roles/ansible.cfg:
--------------------------------------------------------------------------------
1 | [defaults]
2 | inventory=./hosts
3 | deprecation_warnings=False
4 | nocows = 1
5 | duplicate_dict_key=ignore
6 | action_warnings=False
--------------------------------------------------------------------------------
/ansible-roles/hosts:
--------------------------------------------------------------------------------
1 | [webservers]
2 | host1 ansible_host=127.0.0.1 ansible_user=vagrant ansible_port=2222 ansible_ssh_private_key_file=./.vagrant/machines/host1/virtualbox/private_key
--------------------------------------------------------------------------------
/ansible-roles/main_playbook.yml:
--------------------------------------------------------------------------------
1 | - hosts: all
2 | become: true
3 | roles:
4 | - role: webserver
--------------------------------------------------------------------------------
/ansible-roles/roles/test_role/.travis.yml:
--------------------------------------------------------------------------------
1 | ---
2 | language: python
3 | python: "2.7"
4 |
5 | # Use the new container infrastructure
6 | sudo: false
7 |
8 | # Install ansible
9 | addons:
10 | apt:
11 | packages:
12 | - python-pip
13 |
14 | install:
15 | # Install ansible
16 | - pip install ansible
17 |
18 | # Check ansible version
19 | - ansible --version
20 |
21 | # Create ansible.cfg with correct roles_path
22 | - printf '[defaults]\nroles_path=../' >ansible.cfg
23 |
24 | script:
25 | # Basic role syntax check
26 | - ansible-playbook tests/test.yml -i tests/inventory --syntax-check
27 |
28 | notifications:
29 | webhooks: https://galaxy.ansible.com/api/v1/notifications/
--------------------------------------------------------------------------------
/ansible-roles/roles/test_role/README.md:
--------------------------------------------------------------------------------
1 | Role Name
2 | =========
3 |
4 | A brief description of the role goes here.
5 |
6 | Requirements
7 | ------------
8 |
9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
10 |
11 | Role Variables
12 | --------------
13 |
14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
15 |
16 | Dependencies
17 | ------------
18 |
19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
20 |
21 | Example Playbook
22 | ----------------
23 |
24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
25 |
26 | - hosts: servers
27 | roles:
28 | - { role: username.rolename, x: 42 }
29 |
30 | License
31 | -------
32 |
33 | BSD
34 |
35 | Author Information
36 | ------------------
37 |
38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed).
39 |
--------------------------------------------------------------------------------
/ansible-roles/roles/test_role/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # defaults file for test_role
3 |
--------------------------------------------------------------------------------
/ansible-roles/roles/test_role/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # handlers file for test_role
3 |
--------------------------------------------------------------------------------
/ansible-roles/roles/test_role/meta/main.yml:
--------------------------------------------------------------------------------
1 | galaxy_info:
2 | author: your name
3 | description: your role description
4 | company: your company (optional)
5 |
6 | # If the issue tracker for your role is not on github, uncomment the
7 | # next line and provide a value
8 | # issue_tracker_url: http://example.com/issue/tracker
9 |
10 | # Choose a valid license ID from https://spdx.org - some suggested licenses:
11 | # - BSD-3-Clause (default)
12 | # - MIT
13 | # - GPL-2.0-or-later
14 | # - GPL-3.0-only
15 | # - Apache-2.0
16 | # - CC-BY-4.0
17 | license: license (GPL-2.0-or-later, MIT, etc)
18 |
19 | min_ansible_version: 2.1
20 |
21 | # If this a Container Enabled role, provide the minimum Ansible Container version.
22 | # min_ansible_container_version:
23 |
24 | #
25 | # Provide a list of supported platforms, and for each platform a list of versions.
26 | # If you don't wish to enumerate all versions for a particular platform, use 'all'.
27 | # To view available platforms and versions (or releases), visit:
28 | # https://galaxy.ansible.com/api/v1/platforms/
29 | #
30 | # platforms:
31 | # - name: Fedora
32 | # versions:
33 | # - all
34 | # - 25
35 | # - name: SomePlatform
36 | # versions:
37 | # - all
38 | # - 1.0
39 | # - 7
40 | # - 99.99
41 |
42 | galaxy_tags: []
43 | # List tags for your role here, one per line. A tag is a keyword that describes
44 | # and categorizes the role. Users find roles by searching for tags. Be sure to
45 | # remove the '[]' above, if you add tags to this list.
46 | #
47 | # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
48 | # Maximum 20 tags per role.
49 |
50 | dependencies: []
51 | # List your role dependencies here, one per line. Be sure to remove the '[]' above,
52 | # if you add dependencies to this list.
53 |
--------------------------------------------------------------------------------
/ansible-roles/roles/test_role/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # tasks file for test_role
3 |
--------------------------------------------------------------------------------
/ansible-roles/roles/test_role/tests/inventory:
--------------------------------------------------------------------------------
1 | localhost
2 |
3 |
--------------------------------------------------------------------------------
/ansible-roles/roles/test_role/tests/test.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: localhost
3 | remote_user: root
4 | roles:
5 | - test_role
6 |
--------------------------------------------------------------------------------
/ansible-roles/roles/test_role/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # vars file for test_role
3 |
--------------------------------------------------------------------------------
/ansible-roles/roles/webserver/README.md:
--------------------------------------------------------------------------------
1 | Role Name
2 | =========
3 |
4 | This is a role created for demonstration purposes that configures a basic nginx webserver with a minimal configuration.
5 |
6 | Requirements
7 | ------------
8 |
9 | Any prerequisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
10 |
11 | * Ansible
12 | * Jinja2
13 |
14 | Role Variables
15 | --------------
16 |
17 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
18 |
19 | ### defaults/main.yml
20 | Default nginx installation variables.
21 |
22 | * nginx_version: Specific version of nginx to install
23 | * nginx_custom_directory: Custom directory for nginx installation
24 |
25 | ### vars/main.yml
26 | Here we define variables that have high precedence and aren't intended to be changed by the play.
27 |
28 | * nginx_custom_directory: Custom directory for nginx installation
29 |
30 | Dependencies
31 | ------------
32 |
33 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
34 |
35 | Example Playbook
36 | ----------------
37 |
38 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
39 |
40 | - hosts: all
41 | become: true
42 | roles:
43 | - webserver
44 |
45 | License
46 | -------
47 |
48 | Apache-2.0
49 |
50 | Author Information
51 | ------------------
52 |
53 | Ioannis Moustakis
54 |
--------------------------------------------------------------------------------
/ansible-roles/roles/webserver/defaults/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # defaults file for webserver
3 | nginx_version: 1.18.0-0ubuntu1.3
4 | nginx_custom_directory: /var/www/example_domain
--------------------------------------------------------------------------------
/ansible-roles/roles/webserver/files/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello from Ngnix
4 |
5 |
6 | This is our test webserver
7 | This Nginx web server was deployed by Ansible.
8 |
9 |
--------------------------------------------------------------------------------
/ansible-roles/roles/webserver/handlers/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # handlers file for webserver
3 | - name: Restart the Nginx service
4 | service:
5 | name: nginx
6 | state: restarted
--------------------------------------------------------------------------------
/ansible-roles/roles/webserver/meta/main.yml:
--------------------------------------------------------------------------------
1 | galaxy_info:
2 | author: Ioannis Mosutakis
3 | description: Installs nginx and configures a minimal test webserver
4 | company: ACME Corp
5 | license: Apache-2.0
6 | role_name: websercer
7 |
8 | min_ansible_version: "2.1"
9 |
10 | # If this is a Container Enabled role, provide the minimum Ansible Container version.
11 | # min_ansible_container_version:
12 |
13 | #
14 | # Provide a list of supported platforms, and for each platform a list of versions.
15 | # If you don't wish to enumerate all versions for a particular platform, use 'all'.
16 | # To view available platforms and versions (or releases), visit:
17 | # https://galaxy.ansible.com/api/v1/platforms/
18 | #
19 | platforms:
20 | - name: Ubuntu
21 | versions:
22 | - bionic
23 | - focal
24 |
25 | galaxy_tags:
26 | - nginx
27 | - webserver
28 | - development
29 | - test
30 |
31 | dependencies: []
32 | # List your role dependencies here, one per line. Be sure to remove the '[]' above,
33 | # if you add dependencies to this list.
34 |
--------------------------------------------------------------------------------
/ansible-roles/roles/webserver/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # tasks file for webserver
3 | - name: Update and upgrade apt
4 | ansible.builtin.apt:
5 | update_cache: yes
6 | cache_valid_time: 3600
7 | upgrade: yes
8 |
9 | - name: "Install Nginx to version {{ nginx_version }}"
10 | ansible.builtin.apt:
11 | name: "nginx={{ nginx_version }}"
12 | state: present
13 |
14 | - name: Copy the Nginx configuration file to the host
15 | template:
16 | src: templates/nginx.conf.j2
17 | dest: /etc/nginx/sites-available/default
18 |
19 | - name: Create link to the new config to enable it
20 | file:
21 | dest: /etc/nginx/sites-enabled/default
22 | src: /etc/nginx/sites-available/default
23 | state: link
24 |
25 | - name: Create Nginx directory
26 | ansible.builtin.file:
27 | path: "{{ nginx_custom_directory }}"
28 | state: directory
29 |
30 | - name: Copy index.html to the Nginx directory
31 | copy:
32 | src: files/index.html
33 | dest: "{{ nginx_custom_directory }}/index.html"
34 | notify: Restart the Nginx service
--------------------------------------------------------------------------------
/ansible-roles/roles/webserver/templates/nginx.conf.j2:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | listen [::]:80;
4 | root {{ nginx_custom_directory }};
5 | index index.html;
6 | location / {
7 | try_files $uri $uri/ =404;
8 | }
9 | }
--------------------------------------------------------------------------------
/ansible-roles/roles/webserver/vars/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # vars file for webserver
3 | nginx_custom_directory: /home/ubuntu/nginx
--------------------------------------------------------------------------------
/ansible-variables/.gitignore:
--------------------------------------------------------------------------------
1 | .vagrant/
--------------------------------------------------------------------------------
/ansible-variables/README.md:
--------------------------------------------------------------------------------
1 | # Working with Ansible Playbooks
2 | This repository includes all the files related to the [Ansible Variables](https://spacelift.io/blog/ansible-variables) blog post. If you want to run the examples on this repo you can execute `vagrant up` from the top of this repository in order to spin up two local vms to target with Ansible. Requirements to follow along: [Vagrant](https://www.vagrantup.com/docs/installation) and [VirtualBox](https://www.virtualbox.org/).
--------------------------------------------------------------------------------
/ansible-variables/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure
5 | # configures the configuration version (we support older styles for
6 | # backwards compatibility). Please don't change it unless you know what
7 | # you're doing.
8 | Vagrant.configure("2") do |config|
9 | # The most common configuration options are documented and commented below.
10 | # For a complete reference, please see the online documentation at
11 | # https://docs.vagrantup.com.
12 |
13 | # Every Vagrant development environment requires a box. You can search for
14 | # boxes at https://vagrantcloud.com/search.
15 |
16 | config.vm.define "host1" do |host1|
17 | host1.vm.box = "hashicorp/bionic64"
18 | end
19 |
20 | config.vm.define "host2" do |host2|
21 | host2.vm.box = "hashicorp/bionic64"
22 | end
23 |
24 | # Disable automatic box update checking. If you disable this, then
25 | # boxes will only be checked for updates when the user runs
26 | # `vagrant box outdated`. This is not recommended.
27 | # config.vm.box_check_update = false
28 |
29 | # Create a forwarded port mapping which allows access to a specific port
30 | # within the machine from a port on the host machine. In the example below,
31 | # accessing "localhost:8080" will access port 80 on the guest machine.
32 | # NOTE: This will enable public access to the opened port
33 | # config.vm.network "forwarded_port", guest: 80, host: 8080
34 |
35 | # Create a forwarded port mapping which allows access to a specific port
36 | # within the machine from a port on the host machine and only allow access
37 | # via 127.0.0.1 to disable public access
38 | # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
39 |
40 | # Create a private network, which allows host-only access to the machine
41 | # using a specific IP.
42 | # config.vm.network "private_network", ip: "192.168.33.10"
43 |
44 | # Create a public network, which generally matched to bridged network.
45 | # Bridged networks make the machine appear as another physical device on
46 | # your network.
47 | # config.vm.network "public_network"
48 |
49 | # Share an additional folder to the guest VM. The first argument is
50 | # the path on the host to the actual folder. The second argument is
51 | # the path on the guest to mount the folder. And the optional third
52 | # argument is a set of non-required options.
53 | # config.vm.synced_folder "../data", "/vagrant_data"
54 |
55 | # Provider-specific configuration so you can fine-tune various
56 | # backing providers for Vagrant. These expose provider-specific options.
57 | # Example for VirtualBox:
58 | #
59 | # config.vm.provider "virtualbox" do |vb|
60 | # # Display the VirtualBox GUI when booting the machine
61 | # vb.gui = true
62 | #
63 | # # Customize the amount of memory on the VM:
64 | # vb.memory = "1024"
65 | # end
66 | #
67 | # View the documentation for the provider you are using for more
68 | # information on available options.
69 |
70 | # Enable provisioning with a shell script. Additional provisioners such as
71 | # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
72 | # documentation for more information about their specific syntax and use.
73 | # config.vm.provision "shell", inline: <<-SHELL
74 | # apt-get update
75 | # apt-get install -y apache2
76 | # SHELL
77 | end
78 |
--------------------------------------------------------------------------------
/ansible-variables/ansible.cfg:
--------------------------------------------------------------------------------
1 | [defaults]
2 | inventory=./hosts
3 | deprecation_warnings=False
4 | nocows = 1
5 | duplicate_dict_key=ignore
--------------------------------------------------------------------------------
/ansible-variables/example-anchors-aliases.yml:
--------------------------------------------------------------------------------
1 | - name: Example Anchors and Aliases
2 | hosts: all
3 | become: yes
4 | vars:
5 | user_groups: &user_groups
6 | - devs
7 | - support
8 | user_1:
9 | user_info: &user_info
10 | name: bob
11 | groups: *user_groups
12 | state: present
13 | create_home: yes
14 | user_2:
15 | user_info:
16 | <<: *user_info
17 | name: christina
18 | user_3:
19 | user_info:
20 | <<: *user_info
21 | name: jessica
22 | groups: support
23 |
24 | tasks:
25 | - name: Add several groups
26 | ansible.builtin.group:
27 | name: "{{ item }}"
28 | state: present
29 | loop: "{{ user_groups }}"
30 |
31 | - name: Add several users
32 | ansible.builtin.user:
33 | <<: *user_info
34 | name: "{{ item.user_info.name }}"
35 | groups: "{{ item.user_info.groups }}"
36 | loop:
37 | - "{{ user_1 }}"
38 | - "{{ user_2 }}"
39 | - "{{ user_3 }}"
--------------------------------------------------------------------------------
/ansible-variables/example-external-vars.yml:
--------------------------------------------------------------------------------
1 | - name: Example External Variables file
2 | hosts: all
3 | vars_files:
4 | - ./vars/variables.yml
5 |
6 | tasks:
7 | - name: Print the value of variable docker_version
8 | debug:
9 | msg: "{{ docker_version}} "
10 |
11 | - name: Print the value of group variable http_port
12 | debug:
13 | msg: "{{ http_port}} "
14 |
15 | - name: Print the value of host variable app_version
16 | debug:
17 | msg: "{{ app_version}} "
--------------------------------------------------------------------------------
/ansible-variables/example-register-variable-conditionals.yml:
--------------------------------------------------------------------------------
1 | - name: Example Registered Variables Conditionals
2 | hosts: all
3 |
4 | tasks:
5 | - name: Register an example variable
6 | shell: cat /etc/hosts
7 | register: hosts_contents
8 |
9 | - name: Check if hosts file contains the word "localhost"
10 | debug:
11 | msg: "/etc/hosts file contains the word localhost"
12 | when: hosts_contents.stdout.find("localhost") != -1
--------------------------------------------------------------------------------
/ansible-variables/example-register-variable.yml:
--------------------------------------------------------------------------------
1 | - name: Example Register Variable Playbook
2 | hosts: all
3 |
4 | tasks:
5 | - name: Run a script and register the output as a variable
6 | shell: "find hosts"
7 | args:
8 | chdir: "/etc"
9 | register: find_hosts_output
10 | - name: Use the output variable of the previous task
11 | debug:
12 | var: find_hosts_output
--------------------------------------------------------------------------------
/ansible-variables/example-simple-variable.yml:
--------------------------------------------------------------------------------
1 | - name: Example Simple Variable
2 | hosts: all
3 | become: yes
4 | vars:
5 | username: bob
6 |
7 | tasks:
8 | - name: Add the user {{ username }}
9 | ansible.builtin.user:
10 | name: "{{ username }}"
11 | state: present
--------------------------------------------------------------------------------
/ansible-variables/example-variable-types.yml:
--------------------------------------------------------------------------------
1 | - name: Example Variable Types
2 | hosts: all
3 | vars:
4 | username: bob
5 | version:
6 | - v1
7 | - v2
8 | - v3
9 | users:
10 | - user_1: maria
11 | - user_2: peter
12 | - user_3: sophie
13 | cidr_blocks:
14 | production:
15 | vpc_cidr: "172.31.0.0/16"
16 | staging:
17 | vpc_cidr: "10.0.0.0/24"
18 |
19 |
20 |
21 | tasks:
22 | - name: Add the user {{ username }}
23 | ansible.builtin.user:
24 | name: "{{ username }}"
25 | state: present
26 | become: yes
27 |
28 | - name: Print versions
29 | ansible.builtin.debug:
30 | var: version
31 |
32 | - name: Print users
33 | ansible.builtin.debug:
34 | var: users
35 |
36 | - name: Print production vpc_cidr
37 | ansible.builtin.debug:
38 | var: cidr_blocks['production']['vpc_cidr']
--------------------------------------------------------------------------------
/ansible-variables/group_vars/all:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spacelift-io-blog-posts/Blog-Technical-Content/d3fab6d9c6cb030e3e617b0c42e9a46fe797826f/ansible-variables/group_vars/all
--------------------------------------------------------------------------------
/ansible-variables/group_vars/webservers:
--------------------------------------------------------------------------------
1 | http_port: 80
2 | ansible_host: 127.0.0.1
3 | ansible_user: vagrant
--------------------------------------------------------------------------------
/ansible-variables/host_vars/host1:
--------------------------------------------------------------------------------
1 | app_version: 1.0.1
2 | ansible_port: 2222
3 | ansible_ssh_private_key_file: ./.vagrant/machines/host1/virtualbox/private_key
--------------------------------------------------------------------------------
/ansible-variables/host_vars/host2:
--------------------------------------------------------------------------------
1 | app_version: 1.0.2
2 | ansible_port: 2200
3 | ansible_ssh_private_key_file: ./.vagrant/machines/host2/virtualbox/private_key
--------------------------------------------------------------------------------
/ansible-variables/hosts:
--------------------------------------------------------------------------------
1 | [webservers]
2 | host1
3 | host2
--------------------------------------------------------------------------------
/ansible-variables/roles/common/defaults/main.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spacelift-io-blog-posts/Blog-Technical-Content/d3fab6d9c6cb030e3e617b0c42e9a46fe797826f/ansible-variables/roles/common/defaults/main.yml
--------------------------------------------------------------------------------
/ansible-variables/roles/common/vars/main.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spacelift-io-blog-posts/Blog-Technical-Content/d3fab6d9c6cb030e3e617b0c42e9a46fe797826f/ansible-variables/roles/common/vars/main.yml
--------------------------------------------------------------------------------
/ansible-variables/vars/variables.yml:
--------------------------------------------------------------------------------
1 | docker_version: 20.10.12
--------------------------------------------------------------------------------
/az-ad-group-module/ad_group/main.tf:
--------------------------------------------------------------------------------
1 | resource "azuread_group" "ad_group" {
2 | count = 3
3 | display_name = var.ad_group_names[count.index]
4 | security_enabled = true
5 | mail_enabled = false
6 | }
--------------------------------------------------------------------------------
/az-ad-group-module/ad_group/variables.tf:
--------------------------------------------------------------------------------
1 | variable "ad_group_names" {
2 | type = list(string)
3 | description = "List of all the AD Group names"
4 | }
--------------------------------------------------------------------------------
/az-ad-group-module/azure-pipeline.yaml:
--------------------------------------------------------------------------------
1 | stages:
2 | - stage: Build
3 | displayName: Terraform-Plan
4 | jobs:
5 | - job: TerraformPlan
6 | displayName: Terraform-Plan
7 | pool:
8 | name: Private-Build-Agents
9 | steps:
10 | - checkout: self
11 | - script: ls $(System.DefaultWorkingDirectory)
12 | - task: TerraformInstaller@0
13 | displayName: 'Use Terraform latest'
14 |
15 | - task: TerraformCLI@0
16 | displayName: Terraform-Init
17 | inputs:
18 | command: 'init'
19 | workingDirectory: '$(System.DefaultWorkingDirectory)'
20 | backendType: 'azurerm'
21 | backendServiceArm: 'IAC Service Connection-Azure'
22 | backendAzureRmResourceGroupName: 'tf-rg'
23 | backendAzureRmStorageAccountName: 'jacktfstatesa'
24 | backendAzureRmContainerName: 'terraform'
25 | backendAzureRmKey: 'adgroups.tfstate'
26 |
27 | - task: TerraformCLI@0
28 | displayName: Terraform-Plan
29 | inputs:
30 | command: 'plan'
31 | workingDirectory: '$(System.DefaultWorkingDirectory)'
32 | environmentServiceName: 'RG Service Connection'
--------------------------------------------------------------------------------
/az-ad-group-module/main.tf:
--------------------------------------------------------------------------------
1 | provider "azurerm" {
2 | features {}
3 | }
4 |
5 | terraform {
6 | required_providers {
7 | azurerm = {
8 | source = "hashicorp/azurerm"
9 | version = ">=2.95.0"
10 | }
11 | azuread = {
12 | source = "hashicorp/azuread"
13 | }
14 | }
15 | backend "azurerm" {
16 | resource_group_name = "tf-rg"
17 | storage_account_name = "jacktfstatesa"
18 | container_name = "terraform"
19 | key = "adgroups.tfstate"
20 | }
21 | }
22 |
23 | module "ad_group" {
24 | source = "./ad_group"
25 | ad_group_names = var.ad_group_names
26 | }
--------------------------------------------------------------------------------
/az-ad-group-module/terraform.tfvars:
--------------------------------------------------------------------------------
1 | ad_group_names = ["Group1", "Group2", "Group3"]
2 |
--------------------------------------------------------------------------------
/az-ad-group-module/variables.tf:
--------------------------------------------------------------------------------
1 | variable "ad_group_names" {
2 | type = list(string)
3 | description = "List of all the AD Group names"
4 | }
--------------------------------------------------------------------------------
/cdktf-aws-python-webserver/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | imports/*
3 | !imports/__init__.py
4 | .terraform
5 | cdktf.out
6 | cdktf.log
7 | *terraform.*.tfstate*
--------------------------------------------------------------------------------
/cdktf-aws-python-webserver/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | name = "pypi"
3 | url = "https://pypi.org/simple"
4 | verify_ssl = true
5 |
6 | [requires]
7 | python_version = "3"
8 |
9 | [packages]
10 | cdktf = "~=0.15.2"
11 | pytest = "*"
12 | cdktf-cdktf-provider-aws = "~=12.0.2"
13 | constructs = "*"
14 |
--------------------------------------------------------------------------------
/cdktf-aws-python-webserver/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "e26c0c005abc1232f7e0ee8183364511d0f0754da0bb7798fd54a61f559b4f55"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {
19 | "attrs": {
20 | "hashes": [
21 | "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836",
22 | "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"
23 | ],
24 | "markers": "python_version >= '3.6'",
25 | "version": "==22.2.0"
26 | },
27 | "cattrs": {
28 | "hashes": [
29 | "sha256:bc12b1f0d000b9f9bee83335887d532a1d3e99a833d1bf0882151c97d3e68c21",
30 | "sha256:f0eed5642399423cf656e7b66ce92cdc5b963ecafd041d1b24d136fdde7acf6d"
31 | ],
32 | "markers": "python_version >= '3.7'",
33 | "version": "==22.2.0"
34 | },
35 | "cdktf": {
36 | "hashes": [
37 | "sha256:3cd6ad7b918ad4a87fe0477545b35d27c63540068b222460c1037736472920ca",
38 | "sha256:ec5e1838b732bcbc9bbc8e3c4a26e658ffcb0a75cb6eae20b972c93e8131c0a5"
39 | ],
40 | "index": "pypi",
41 | "version": "==0.15.2"
42 | },
43 | "cdktf-cdktf-provider-aws": {
44 | "hashes": [
45 | "sha256:356d7474e4401d1422c28144a7081d41c5d08826ee50fcf77fc909f86ba27c52",
46 | "sha256:567d6f6be42cdd77e25e292e0786109fb7d1982ce9b10e2d67d4bd7b6eba061d"
47 | ],
48 | "index": "pypi",
49 | "version": "==12.0.2"
50 | },
51 | "constructs": {
52 | "hashes": [
53 | "sha256:85f6d715d69ae68deaa5f701c2df24a3a663cc96ac6ebc8b19fd6fe7f23ebab9",
54 | "sha256:9436ab72590d302ccec87ccfee7d936f72184330e459c19f2b2b37c42d5d622a"
55 | ],
56 | "markers": "python_version ~= '3.7'",
57 | "version": "==10.1.241"
58 | },
59 | "exceptiongroup": {
60 | "hashes": [
61 | "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e",
62 | "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"
63 | ],
64 | "markers": "python_version < '3.11'",
65 | "version": "==1.1.0"
66 | },
67 | "iniconfig": {
68 | "hashes": [
69 | "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
70 | "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
71 | ],
72 | "markers": "python_version >= '3.7'",
73 | "version": "==2.0.0"
74 | },
75 | "jsii": {
76 | "hashes": [
77 | "sha256:575131396ad34f8f6e9f2604953ecbf4f3368625656a828b13089e4abb81b443",
78 | "sha256:ee76781fe66106c367fbb3bb383db4f5e9b8ff3d3c4c0f34624c050211f040be"
79 | ],
80 | "markers": "python_version ~= '3.7'",
81 | "version": "==1.74.0"
82 | },
83 | "packaging": {
84 | "hashes": [
85 | "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2",
86 | "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"
87 | ],
88 | "markers": "python_version >= '3.7'",
89 | "version": "==23.0"
90 | },
91 | "pluggy": {
92 | "hashes": [
93 | "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159",
94 | "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"
95 | ],
96 | "markers": "python_version >= '3.6'",
97 | "version": "==1.0.0"
98 | },
99 | "publication": {
100 | "hashes": [
101 | "sha256:0248885351febc11d8a1098d5c8e3ab2dabcf3e8c0c96db1e17ecd12b53afbe6",
102 | "sha256:68416a0de76dddcdd2930d1c8ef853a743cc96c82416c4e4d3b5d901c6276dc4"
103 | ],
104 | "version": "==0.0.3"
105 | },
106 | "pytest": {
107 | "hashes": [
108 | "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5",
109 | "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"
110 | ],
111 | "index": "pypi",
112 | "version": "==7.2.1"
113 | },
114 | "python-dateutil": {
115 | "hashes": [
116 | "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
117 | "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
118 | ],
119 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
120 | "version": "==2.8.2"
121 | },
122 | "six": {
123 | "hashes": [
124 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
125 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
126 | ],
127 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
128 | "version": "==1.16.0"
129 | },
130 | "tomli": {
131 | "hashes": [
132 | "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
133 | "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
134 | ],
135 | "markers": "python_version < '3.11'",
136 | "version": "==2.0.1"
137 | },
138 | "typeguard": {
139 | "hashes": [
140 | "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4",
141 | "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"
142 | ],
143 | "markers": "python_full_version >= '3.5.3'",
144 | "version": "==2.13.3"
145 | },
146 | "typing-extensions": {
147 | "hashes": [
148 | "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa",
149 | "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"
150 | ],
151 | "markers": "python_version >= '3.7'",
152 | "version": "==4.4.0"
153 | }
154 | },
155 | "develop": {}
156 | }
157 |
--------------------------------------------------------------------------------
/cdktf-aws-python-webserver/README.md:
--------------------------------------------------------------------------------
1 | # cdktf-aws-python-webserver
2 | This repository containers CDK for Terraform files to provision AWS infrastructure for a web server with a loadbalancer and other necessary resources via Python
3 |
--------------------------------------------------------------------------------
/cdktf-aws-python-webserver/cdktf.json:
--------------------------------------------------------------------------------
1 | {
2 | "language": "python",
3 | "app": "pipenv run python main.py",
4 | "projectId": "ec6738d5-5da2-4f77-9bc4-42480495df6d",
5 | "sendCrashReports": "false",
6 | "terraformProviders": [],
7 | "terraformModules": [
8 | {
9 | "name": "vpc",
10 | "source": "terraform-aws-modules/vpc/aws",
11 | "version": "3.19.0"
12 | }
13 | ],
14 | "codeMakerOutput": "imports",
15 | "context": {
16 | "excludeStackIdFromLogicalIds": "true",
17 | "allowSepCharsInLogicalIds": "true"
18 | }
19 | }
--------------------------------------------------------------------------------
/cdktf-aws-python-webserver/help:
--------------------------------------------------------------------------------
1 | ========================================================================================================
2 |
3 | Your cdktf Python project is ready!
4 |
5 | cat help Prints this message
6 |
7 | Compile:
8 | pipenv run ./main.py Compile and run the python code.
9 |
10 | Synthesize:
11 | cdktf synth [stack] Synthesize Terraform resources to cdktf.out/
12 |
13 | Diff:
14 | cdktf diff [stack] Perform a diff (terraform plan) for the given stack
15 |
16 | Deploy:
17 | cdktf deploy [stack] Deploy the given stack
18 |
19 | Destroy:
20 | cdktf destroy [stack] Destroy the given stack
21 |
22 | Learn more about using modules and providers https://cdk.tf/modules-and-providers
23 |
24 | Use Providers:
25 |
26 | You can add prebuilt providers (if available) or locally generated ones using the add command:
27 |
28 | cdktf provider add "aws@~>3.0" null kreuzwerker/docker
29 |
30 | You can find all prebuilt providers on PyPI: https://pypi.org/user/cdktf-team/
31 | You can also install these providers directly through pipenv:
32 |
33 | pipenv install cdktf-cdktf-provider-aws
34 | pipenv install cdktf-cdktf-provider-google
35 | pipenv install cdktf-cdktf-provider-azurerm
36 | pipenv install cdktf-cdktf-provider-docker
37 | pipenv install cdktf-cdktf-provider-github
38 | pipenv install cdktf-cdktf-provider-null
39 |
40 | You can also build any module or provider locally. Learn more: https://cdk.tf/modules-and-providers
41 |
42 | ========================================================================================================
--------------------------------------------------------------------------------
/cdktf-aws-python-webserver/main-test.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from cdktf import Testing
3 |
4 | # The tests below are example tests, you can find more information at
5 | # https://cdk.tf/testing
6 |
7 | class TestMain:
8 |
9 | def test_my_app(self):
10 | assert True
11 |
12 | #stack = TerraformStack(Testing.app(), "stack")
13 | #app_abstraction = MyApplicationsAbstraction(stack, "app-abstraction")
14 | #synthesized = Testing.synth(stack)
15 |
16 | #def test_should_contain_container(self):
17 | # assert Testing.to_have_resource(self.synthesized, Container.TF_RESOURCE_TYPE)
18 |
19 | #def test_should_use_an_ubuntu_image(self):
20 | # assert Testing.to_have_resource_with_properties(self.synthesized, Image.TF_RESOURCE_TYPE, {
21 | # "name": "ubuntu:latest",
22 | # })
23 |
24 | #def test_check_validity(self):
25 | # assert Testing.to_be_valid_terraform(Testing.full_synth(stack))
--------------------------------------------------------------------------------
/cdktf-aws-python-webserver/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from constructs import Construct
3 | from cdktf import App, TerraformStack, TerraformOutput, TerraformVariable, Token, Fn
4 | from cdktf_cdktf_provider_aws.provider import AwsProvider
5 | from imports.vpc import Vpc
6 | import cdktf_cdktf_provider_aws.alb as Alb_
7 | import cdktf_cdktf_provider_aws.alb_listener as AlbListener_
8 | import cdktf_cdktf_provider_aws.alb_target_group_attachment as AlbTargetGroupAttachment_
9 | import cdktf_cdktf_provider_aws.alb_target_group as AlbTargetGroup_
10 | import cdktf_cdktf_provider_aws.security_group as SecurityGroup_
11 | from cdktf_cdktf_provider_aws.instance import Instance
12 |
13 |
14 | class MyStack(TerraformStack):
15 | def __init__(self, scope: Construct, id: str):
16 | super().__init__(scope, id)
17 |
18 | AwsProvider(self, "AWS", region="eu-west-2")
19 |
20 | image_id = TerraformVariable(self, "image_id",
21 | type="string",
22 | default="ami-08cd358d745620807",
23 | description="AMI for the web server"
24 | )
25 |
26 | instance_type = TerraformVariable(self, "instance_type",
27 | type="string",
28 | default="t2.micro",
29 | description="Instance type for the web server"
30 | )
31 |
32 | webserver_vpc = Vpc(self, "vpc_name",
33 | name="web_server",
34 | cidr="10.10.0.0/16",
35 | azs=["eu-west-2a", "eu-west-2b", "eu-west-2c"],
36 | public_subnets=["10.10.1.0/24",
37 | "10.10.2.0/24", "10.10.3.0/24"],
38 | private_subnets=["10.10.4.0/24",
39 | "10.10.5.0/24", "10.10.6.0/24"],
40 | enable_nat_gateway=True
41 | )
42 |
43 | alb_security_group = SecurityGroup_.SecurityGroup(self, "alb_security_group",
44 | name="alb_sg",
45 | description="Security group for alb with HTTP ports open from anywhere",
46 | vpc_id=Token().as_string(webserver_vpc.vpc_id_output),
47 | ingress=[SecurityGroup_.SecurityGroupIngress(
48 | from_port=80, to_port=80, protocol="tcp", cidr_blocks=["0.0.0.0/0"])],
49 | egress=[SecurityGroup_.SecurityGroupEgress(
50 | from_port=0, to_port=0, protocol="-1", cidr_blocks=["0.0.0.0/0"])]
51 | )
52 |
53 | web_server_security_group = SecurityGroup_.SecurityGroup(self, "web_server_security_group",
54 | name="web_server_sg",
55 | description="Security group for web-server with HTTP ports open from alb",
56 | vpc_id=Token().as_string(webserver_vpc.vpc_id_output),
57 | ingress=[SecurityGroup_.SecurityGroupIngress(
58 | from_port=80, to_port=80, protocol="tcp", security_groups=[alb_security_group.id])],
59 | egress=[SecurityGroup_.SecurityGroupEgress(
60 | from_port=0, to_port=0, protocol="-1", cidr_blocks=["0.0.0.0/0"])]
61 | )
62 |
63 | web_server = Instance(self, "compute",
64 | ami=image_id.default,
65 | instance_type=instance_type.default,
66 | vpc_security_group_ids=[
67 | web_server_security_group.id],
68 | subnet_id=Fn.element(Token().as_list(
69 | webserver_vpc.public_subnets_output), 0),
70 | user_data="""#!/bin/bash
71 | sudo yum update -y
72 | sudo yum install httpd -y
73 | sudo systemctl enable httpd
74 | sudo systemctl start httpd
75 | echo "Congrats you provisioned this web server with CDK for Terraform!
" > /var/www/html/index.html"""
76 |
77 | )
78 |
79 | web_server_alb = Alb_.Alb(self, "web_server_alb",
80 | load_balancer_type="application",
81 | subnets=Token().as_list(webserver_vpc.public_subnets_output),
82 | security_groups=[alb_security_group.id]
83 |
84 | )
85 |
86 | web_server_alb_target_group = AlbTargetGroup_.AlbTargetGroup(
87 | self,
88 | "web_server_alb_target_group",
89 | name="webServerAlbTargetGroup",
90 | port=80,
91 | vpc_id=Token().as_string(webserver_vpc.vpc_id_output),
92 | protocol="HTTP",
93 | target_type="instance"
94 | )
95 |
96 | web_server_alb_listener = AlbListener_.AlbListener(self, "web_server_alb_listener",
97 | load_balancer_arn=web_server_alb.id,
98 | port=80,
99 | protocol="HTTP",
100 | default_action=[AlbListener_.AlbListenerDefaultAction(
101 | type="forward", target_group_arn=web_server_alb_target_group.arn)]
102 | )
103 |
104 | web_server_alb_target_group_attachment = AlbTargetGroupAttachment_.AlbTargetGroupAttachment(self, "web_server_alb_target_group_attachment",
105 | target_group_arn=web_server_alb_target_group.arn,
106 | target_id=web_server.id,
107 | port=80
108 | )
109 |
110 | TerraformOutput(self, "alb_dns",
111 | value=web_server_alb.dns_name
112 | )
113 |
114 |
115 | app = App()
116 | MyStack(app, "cdktf-aws-python-webserver")
117 |
118 | app.synth()
119 |
--------------------------------------------------------------------------------
/eks-blueprints-terraform/README.md:
--------------------------------------------------------------------------------
1 | # eks-blueprints-terraform-demo
2 | This repository includes all the files related to this EKS Blueprints for Terraform blog post.
--------------------------------------------------------------------------------
/eks-blueprints-terraform/dev_teams.tf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | #Dev Teams
3 | ###############################################################################
4 |
5 | module "eks_blueprints_dev_teams" {
6 | source = "aws-ia/eks-blueprints-teams/aws"
7 | version = "~> 1.0"
8 |
9 | for_each = {
10 | a = {
11 | labels = {
12 | "elbv2.k8s.aws/pod-readiness-gate-inject" = "enabled",
13 | "appName" = "team-a-app",
14 | "projectName" = "project-a",
15 | }
16 | }
17 | b = {
18 | labels = {
19 | "elbv2.k8s.aws/pod-readiness-gate-inject" = "enabled",
20 | "appName" = "team-b-app",
21 | "projectName" = "project-b",
22 | }
23 | }
24 | }
25 | name = "team-${each.key}"
26 |
27 | users = [data.aws_caller_identity.current.arn]
28 | cluster_arn = module.eks.cluster_arn
29 | oidc_provider_arn = module.eks.oidc_provider_arn
30 |
31 | labels = merge(
32 | {
33 | team = each.key
34 | },
35 | try(each.value.labels, {})
36 | )
37 |
38 | annotations = {
39 | team = each.key
40 | }
41 |
42 | namespaces = {
43 | "team-${each.key}" = {
44 | labels = merge(
45 | {
46 | team = each.key
47 | },
48 | try(each.value.labels, {})
49 | )
50 |
51 | resource_quota = {
52 | hard = {
53 | "requests.cpu" = "100",
54 | "requests.memory" = "20Gi",
55 | "limits.cpu" = "200",
56 | "limits.memory" = "50Gi",
57 | "pods" = "15",
58 | "secrets" = "10",
59 | "services" = "20"
60 | }
61 | }
62 |
63 | limit_range = {
64 | limit = [
65 | {
66 | type = "Pod"
67 | max = {
68 | cpu = "2"
69 | memory = "1Gi"
70 | }
71 | min = {
72 | cpu = "10m"
73 | memory = "4Mi"
74 | }
75 | },
76 | {
77 | type = "PersistentVolumeClaim"
78 | min = {
79 | storage = "24M"
80 | }
81 | },
82 | {
83 | type = "Container"
84 | default = {
85 | cpu = "50m"
86 | memory = "24Mi"
87 | }
88 | }
89 | ]
90 | }
91 | }
92 | }
93 |
94 | tags = local.tags
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/eks-blueprints-terraform/eks_blueprints_addons.tf:
--------------------------------------------------------------------------------
1 | provider "helm" {
2 | kubernetes {
3 | host = module.eks.cluster_endpoint
4 | cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
5 |
6 | exec {
7 | api_version = "client.authentication.k8s.io/v1beta1"
8 | command = "aws"
9 | # This requires the awscli to be installed locally where Terraform is executed
10 | args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
11 | }
12 | }
13 | }
14 |
15 |
16 | module "eks_blueprints_addons" {
17 | source = "aws-ia/eks-blueprints-addons/aws"
18 | version = "~> 1.0"
19 |
20 | cluster_name = module.eks.cluster_name
21 | cluster_endpoint = module.eks.cluster_endpoint
22 | cluster_version = module.eks.cluster_version
23 | oidc_provider_arn = module.eks.oidc_provider_arn
24 |
25 | enable_aws_load_balancer_controller = true
26 | enable_metrics_server = true
27 | enable_karpenter = true
28 | karpenter = {
29 | repository_username = data.aws_ecrpublic_authorization_token.token.user_name
30 | repository_password = data.aws_ecrpublic_authorization_token.token.password
31 | }
32 |
33 | tags = local.tags
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/eks-blueprints-terraform/initial_skeleton/main.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = local.region
3 | }
4 |
5 |
6 | provider "kubernetes" {
7 | host = module.eks.cluster_endpoint
8 | cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
9 | exec {
10 | api_version = "client.authentication.k8s.io/v1beta1"
11 | command = "aws"
12 | # This requires the awscli to be installed locally where Terraform is executed
13 | args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
14 | }
15 | }
16 |
17 |
18 | data "aws_availability_zones" "available" {}
19 |
20 |
21 | # Find the user currently in use by AWS
22 | data "aws_caller_identity" "current" {}
23 |
24 |
25 | data "aws_iam_role" "eks_admin_role_name" {
26 | count = local.eks_admin_role_name != "" ? 1 : 0
27 | name = local.eks_admin_role_name
28 | }
29 |
30 |
31 | data "aws_ecrpublic_authorization_token" "token" {}
32 |
33 |
34 | locals {
35 | name = var.environment_name
36 | region = var.aws_region
37 | vpc_cidr = var.vpc_cidr
38 | num_of_subnets = min(length(data.aws_availability_zones.available.names), 3)
39 | azs = slice(data.aws_availability_zones.available.names, 0, local.num_of_subnets)
40 | eks_admin_role_name = var.eks_admin_role_name
41 | tags = {
42 | Blueprint = local.name
43 | GithubRepo = "github.com/aws-ia/terraform-aws-eks-blueprints"
44 | }
45 | }
46 |
47 |
48 | ################################################################################
49 | # VPC
50 | ################################################################################
51 | module "vpc" {
52 | source = "terraform-aws-modules/vpc/aws"
53 | version = "~> 5.0.0"
54 | name = "eks_vpc"
55 | cidr = var.vpc_cidr
56 | azs = local.azs
57 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 6, k)]
58 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 6, k + 10)]
59 |
60 |
61 | enable_nat_gateway = true
62 | create_igw = true
63 | enable_dns_hostnames = true
64 | single_nat_gateway = true
65 |
66 |
67 | manage_default_network_acl = true
68 | default_network_acl_tags = { Name = "${local.name}-default" }
69 | manage_default_route_table = true
70 | default_route_table_tags = { Name = "${local.name}-default" }
71 | manage_default_security_group = true
72 | default_security_group_tags = { Name = "${local.name}-default" }
73 |
74 |
75 | public_subnet_tags = {
76 | "kubernetes.io/role/elb" = 1
77 | "kubernetes.io/cluster/${var.environment_name}" = "owned"
78 | }
79 |
80 |
81 | private_subnet_tags = {
82 | "kubernetes.io/role/internal-elb" = 1
83 | "kubernetes.io/cluster/${var.environment_name}" = "owned"
84 | "karpenter.sh/discovery" = local.name
85 | }
86 | }
87 |
88 |
89 | ################################################################################
90 | # Cluster
91 | ################################################################################
92 |
93 |
94 | module "eks" {
95 | source = "terraform-aws-modules/eks/aws"
96 | version = "~> 19.15"
97 |
98 |
99 | cluster_name = local.name
100 | cluster_version = "1.27"
101 | cluster_endpoint_public_access = true
102 |
103 |
104 | # EKS Addons
105 | cluster_addons = {
106 | coredns = {}
107 | kube-proxy = {}
108 | vpc-cni = {}
109 | aws-ebs-csi-driver = {
110 | service_account_role_arn = module.ebs_csi_driver_irsa.iam_role_arn
111 | }
112 |
113 |
114 | }
115 |
116 |
117 | vpc_id = module.vpc.vpc_id
118 | subnet_ids = module.vpc.private_subnets
119 |
120 |
121 | eks_managed_node_groups = {
122 | initial = {
123 | instance_types = ["m5.large"]
124 |
125 |
126 | min_size = 1
127 | max_size = 5
128 | desired_size = 2
129 | }
130 | }
131 |
132 | manage_aws_auth_configmap = true
133 | aws_auth_roles = flatten([
134 | {
135 | # The ARN of the IAM role
136 | rolearn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${local.eks_admin_role_name}"
137 | # The user name within Kubernetes to map to the IAM role
138 | username = "ops-role"
139 | # A list of groups within Kubernetes to which the role is mapped; Checkout K8s Role and Rolebindings
140 | groups = ["system:masters"]
141 | }
142 | ])
143 |
144 |
145 | tags = merge(local.tags, {
146 | # NOTE - if creating multiple security groups with this module, only tag the
147 | # security group that Karpenter should utilize with the following tag
148 | # (i.e. - at most, only one security group should have this tag in your account)
149 | "karpenter.sh/discovery" = local.name
150 | })
151 | }
152 | module "ebs_csi_driver_irsa" {
153 | source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
154 | version = "~> 5.20"
155 |
156 |
157 | # create_role = false
158 | role_name_prefix = "${module.eks.cluster_name}-ebs-csi-driver-"
159 |
160 |
161 | attach_ebs_csi_policy = true
162 |
163 |
164 | oidc_providers = {
165 | main = {
166 | rovider_arn = module.eks.oidc_provider_arn
167 | namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
168 | }
169 | }
170 |
171 |
172 | tags = local.tags
173 | }
174 |
--------------------------------------------------------------------------------
/eks-blueprints-terraform/initial_skeleton/variables.tf:
--------------------------------------------------------------------------------
1 | variable "environment_name" {
2 | description = "The name of environment."
3 | type = string
4 | default = "eks_blueprints"
5 | }
6 |
7 |
8 | variable "aws_region" {
9 | description = "AWS Region"
10 | type = string
11 | default = "us-east-1"
12 | }
13 |
14 |
15 | variable "vpc_cidr" {
16 | description = "CIDR block for VPC"
17 | type = string
18 | default = "10.0.0.0/16"
19 | }
20 |
21 |
22 | variable "eks_admin_role_name" {
23 | type = string
24 | description = "Additional IAM role to be admin in the cluster"
25 | default = ""
26 | }
27 |
--------------------------------------------------------------------------------
/eks-blueprints-terraform/initial_skeleton/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0"
3 |
4 | required_providers {
5 | aws = {
6 | source = "hashicorp/aws"
7 | version = ">= 4.47"
8 | }
9 | helm = {
10 | source = "hashicorp/helm"
11 | version = ">= 2.9"
12 | }
13 | kubernetes = {
14 | source = "hashicorp/kubernetes"
15 | version = ">= 2.20"
16 | }
17 | random = {
18 | source = "hashicorp/random"
19 | version = ">= 3.5"
20 | }
21 | bcrypt = {
22 | source = "viktorradnai/bcrypt"
23 | version = ">= 0.1.2"
24 | }
25 | kubectl = {
26 | source = "gavinbunney/kubectl"
27 | version = ">= 1.14"
28 | }
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/eks-blueprints-terraform/karpenter.tf:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # Karpenter
3 | ################################################################################
4 |
5 | resource "kubectl_manifest" "karpenter_provisioner" {
6 | yaml_body = <<-YAML
7 | apiVersion: karpenter.sh/v1alpha5
8 | kind: Provisioner
9 | metadata:
10 | name: default
11 | spec:
12 | requirements:
13 | - key: "karpenter.k8s.aws/instance-category"
14 | operator: In
15 | values: ["c", "m"]
16 | - key: "karpenter.k8s.aws/instance-cpu"
17 | operator: In
18 | values: ["8", "16", "32"]
19 | - key: "karpenter.k8s.aws/instance-hypervisor"
20 | operator: In
21 | values: ["nitro"]
22 | - key: "topology.kubernetes.io/zone"
23 | operator: In
24 | values: ${jsonencode(local.azs)}
25 | - key: "kubernetes.io/arch"
26 | operator: In
27 | values: ["arm64", "amd64"]
28 | - key: "karpenter.sh/capacity-type" # If not included, the webhook for the AWS cloud provider will default to on-demand
29 | operator: In
30 | values: ["spot", "on-demand"]
31 | kubeletConfiguration:
32 | containerRuntime: containerd
33 | maxPods: 110
34 | limits:
35 | resources:
36 | cpu: 1000
37 | consolidation:
38 | enabled: true
39 | providerRef:
40 | name: default
41 | ttlSecondsUntilExpired: 604800 # 7 Days = 7 * 24 * 60 * 60 Seconds
42 | YAML
43 |
44 | depends_on = [
45 | module.eks_blueprints_addons
46 | ]
47 | }
48 |
49 | resource "kubectl_manifest" "karpenter_node_template" {
50 | yaml_body = <<-YAML
51 | apiVersion: karpenter.k8s.aws/v1alpha1
52 | kind: AWSNodeTemplate
53 | metadata:
54 | name: default
55 | spec:
56 | subnetSelector:
57 | karpenter.sh/discovery: ${module.eks.cluster_name}
58 | securityGroupSelector:
59 | karpenter.sh/discovery: ${module.eks.cluster_name}
60 | instanceProfile: ${module.eks_blueprints_addons.karpenter.node_instance_profile_name}
61 | tags:
62 | karpenter.sh/discovery: ${module.eks.cluster_name}
63 | YAML
64 | }
--------------------------------------------------------------------------------
/eks-blueprints-terraform/main.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = local.region
3 | }
4 |
5 | provider "kubernetes" {
6 | host = module.eks.cluster_endpoint
7 | cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
8 | exec {
9 | api_version = "client.authentication.k8s.io/v1beta1"
10 | command = "aws"
11 | # This requires the awscli to be installed locally where Terraform is executed
12 | args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
13 | }
14 | }
15 |
16 | data "aws_availability_zones" "available" {}
17 |
18 | # Find the user currently in use by AWS
19 | data "aws_caller_identity" "current" {}
20 |
21 | data "aws_iam_role" "eks_admin_role_name" {
22 | count = local.eks_admin_role_name != "" ? 1 : 0
23 | name = local.eks_admin_role_name
24 | }
25 |
26 | data "aws_ecrpublic_authorization_token" "token" {}
27 |
28 | locals {
29 | name = var.environment_name
30 | region = var.aws_region
31 | vpc_cidr = var.vpc_cidr
32 | num_of_subnets = min(length(data.aws_availability_zones.available.names), 3)
33 | azs = slice(data.aws_availability_zones.available.names, 0, local.num_of_subnets)
34 | eks_admin_role_name = var.eks_admin_role_name
35 | tags = {
36 | Blueprint = local.name
37 | GithubRepo = "github.com/aws-ia/terraform-aws-eks-blueprints"
38 | }
39 | }
40 |
41 | ################################################################################
42 | # VPC
43 | ################################################################################
44 | module "vpc" {
45 | source = "terraform-aws-modules/vpc/aws"
46 | version = "~> 5.0.0"
47 | name = "eks_vpc"
48 | cidr = var.vpc_cidr
49 | azs = local.azs
50 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 6, k)]
51 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 6, k + 10)]
52 |
53 | enable_nat_gateway = true
54 | create_igw = true
55 | enable_dns_hostnames = true
56 | single_nat_gateway = true
57 |
58 | manage_default_network_acl = true
59 | default_network_acl_tags = { Name = "${local.name}-default" }
60 | manage_default_route_table = true
61 | default_route_table_tags = { Name = "${local.name}-default" }
62 | manage_default_security_group = true
63 | default_security_group_tags = { Name = "${local.name}-default" }
64 |
65 | public_subnet_tags = {
66 | "kubernetes.io/role/elb" = 1
67 | "kubernetes.io/cluster/${var.environment_name}" = "owned"
68 | }
69 |
70 | private_subnet_tags = {
71 | "kubernetes.io/role/internal-elb" = 1
72 | "kubernetes.io/cluster/${var.environment_name}" = "owned"
73 | "karpenter.sh/discovery" = local.name
74 | }
75 | }
76 |
77 | ################################################################################
78 | # Cluster
79 | ################################################################################
80 |
81 | module "eks" {
82 | source = "terraform-aws-modules/eks/aws"
83 | version = "~> 19.15"
84 |
85 | cluster_name = local.name
86 | cluster_version = "1.27"
87 | cluster_endpoint_public_access = true
88 |
89 | # EKS Addons
90 | cluster_addons = {
91 | coredns = {}
92 | kube-proxy = {}
93 | vpc-cni = {}
94 | aws-ebs-csi-driver = {
95 | service_account_role_arn = module.ebs_csi_driver_irsa.iam_role_arn
96 | }
97 | }
98 |
99 | vpc_id = module.vpc.vpc_id
100 | subnet_ids = module.vpc.private_subnets
101 |
102 | eks_managed_node_groups = {
103 | initial = {
104 | instance_types = ["m5.large"]
105 |
106 | min_size = 1
107 | max_size = 5
108 | desired_size = 2
109 | }
110 | }
111 |
112 | manage_aws_auth_configmap = true
113 | aws_auth_roles = flatten([
114 | {
115 | # The ARN of the IAM role
116 | rolearn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${local.eks_admin_role_name}"
117 | # The user name within Kubernetes to map to the IAM role
118 | username = "ops-role"
119 | # A list of groups within Kubernetes to which the role is mapped; Checkout K8s Role and Rolebindings
120 | groups = ["system:masters"]
121 | },
122 | module.eks_blueprints_platform_team.aws_auth_configmap_role,
123 | [for team in module.eks_blueprints_dev_teams : team.aws_auth_configmap_role],
124 | {
125 | rolearn = module.eks_blueprints_addons.karpenter.node_iam_role_arn
126 | username = "system:node:{{EC2PrivateDNSName}}"
127 | groups = [
128 | "system:bootstrappers",
129 | "system:nodes",
130 | ]
131 | }
132 | ])
133 |
134 | tags = merge(local.tags, {
135 | # NOTE - if creating multiple security groups with this module, only tag the
136 | # security group that Karpenter should utilize with the following tag
137 | # (i.e. - at most, only one security group should have this tag in your account)
138 | "karpenter.sh/discovery" = local.name
139 | })
140 | }
141 |
142 | module "ebs_csi_driver_irsa" {
143 | source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
144 | version = "~> 5.20"
145 |
146 | # create_role = false
147 | role_name_prefix = "${module.eks.cluster_name}-ebs-csi-driver-"
148 |
149 | attach_ebs_csi_policy = true
150 |
151 | oidc_providers = {
152 | main = {
153 | provider_arn = module.eks.oidc_provider_arn
154 | namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
155 | }
156 | }
157 |
158 | tags = local.tags
159 | }
160 |
--------------------------------------------------------------------------------
/eks-blueprints-terraform/outputs.tf:
--------------------------------------------------------------------------------
1 | output "eks_blueprints_platform_teams_configure_kubectl" {
2 | description = "Configure kubectl for Platform Team: make sure you're logged in with the correct AWS profile and run the following command to update your kubeconfig"
3 | value = "aws eks --region ${var.aws_region} update-kubeconfig --name ${module.eks.cluster_name} --role-arn ${module.eks_blueprints_platform_team.iam_role_arn}"
4 | }
5 |
6 | output "eks_blueprints_dev_teams_configure_kubectl" {
7 | description = "Configure kubectl for each Dev Application Teams: make sure you're logged in with the correct AWS profile and run the following command to update your kubeconfig"
8 | value = [for team in module.eks_blueprints_dev_teams : "aws eks --region ${var.aws_region} update-kubeconfig --name ${module.eks.cluster_name} --role-arn ${team.iam_role_arn}"]
9 | }
--------------------------------------------------------------------------------
/eks-blueprints-terraform/platform_team.tf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | #Team Management
3 | ###############################################################################
4 |
5 | provider "kubectl" {
6 | apply_retry_count = 10
7 | host = module.eks.cluster_endpoint
8 | cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
9 | load_config_file = false
10 |
11 | exec {
12 | api_version = "client.authentication.k8s.io/v1beta1"
13 | command = "aws"
14 | # This requires the awscli to be installed locally where Terraform is executed
15 | args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
16 | }
17 | }
18 |
19 |
20 | ###############################################################################
21 | #Platform Team
22 | ###############################################################################
23 |
24 | module "eks_blueprints_platform_team" {
25 | source = "aws-ia/eks-blueprints-teams/aws"
26 | version = "~> 1.0"
27 |
28 | name = "platform-team"
29 |
30 | # Enables elevated, admin privileges for this team
31 | enable_admin = true
32 |
33 | # Define who can impersonate the team-platform Role
34 | users = [
35 | data.aws_caller_identity.current.arn,
36 | try(data.aws_iam_role.eks_admin_role_name[0].arn, data.aws_caller_identity.current.arn),
37 | ]
38 | cluster_arn = module.eks.cluster_arn
39 | oidc_provider_arn = module.eks.oidc_provider_arn
40 |
41 | labels = {
42 | "elbv2.k8s.aws/pod-readiness-gate-inject" = "enabled",
43 | "appName" = "platform-team-app",
44 | "projectName" = "project-platform",
45 | }
46 |
47 | annotations = {
48 | team = "platform"
49 | }
50 |
51 | namespaces = {
52 | "team-platform" = {
53 |
54 | resource_quota = {
55 | hard = {
56 | "requests.cpu" = "10000m",
57 | "requests.memory" = "20Gi",
58 | "limits.cpu" = "20000m",
59 | "limits.memory" = "50Gi",
60 | "pods" = "20",
61 | "secrets" = "20",
62 | "services" = "20"
63 | }
64 | }
65 |
66 | limit_range = {
67 | limit = [
68 | {
69 | type = "Pod"
70 | max = {
71 | cpu = "1000m"
72 | memory = "1Gi"
73 | },
74 | min = {
75 | cpu = "10m"
76 | memory = "4Mi"
77 | }
78 | },
79 | {
80 | type = "PersistentVolumeClaim"
81 | min = {
82 | storage = "24M"
83 | }
84 | }
85 | ]
86 | }
87 | }
88 |
89 | }
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/eks-blueprints-terraform/variables.tf:
--------------------------------------------------------------------------------
1 | variable "environment_name" {
2 | description = "The name of environment."
3 | type = string
4 | default = "eks_blueprints"
5 | }
6 |
7 | variable "aws_region" {
8 | description = "AWS Region"
9 | type = string
10 | default = "us-east-1"
11 | }
12 |
13 | variable "vpc_cidr" {
14 | description = "CIDR block for VPC"
15 | type = string
16 | default = "10.0.0.0/16"
17 | }
18 |
19 | variable "eks_admin_role_name" {
20 | type = string
21 | description = "Additional IAM role to be admin in the cluster"
22 | default = ""
23 | }
--------------------------------------------------------------------------------
/eks-blueprints-terraform/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0"
3 |
4 | required_providers {
5 | aws = {
6 | source = "hashicorp/aws"
7 | version = ">= 4.47"
8 | }
9 | helm = {
10 | source = "hashicorp/helm"
11 | version = ">= 2.9"
12 | }
13 | kubernetes = {
14 | source = "hashicorp/kubernetes"
15 | version = ">= 2.20"
16 | }
17 | random = {
18 | source = "hashicorp/random"
19 | version = ">= 3.5"
20 | }
21 | bcrypt = {
22 | source = "viktorradnai/bcrypt"
23 | version = ">= 0.1.2"
24 | }
25 | kubectl = {
26 | source = "gavinbunney/kubectl"
27 | version = ">= 1.14"
28 | }
29 | }
30 |
31 | }
--------------------------------------------------------------------------------
/iac-examples/README.MD:
--------------------------------------------------------------------------------
1 | Examples from the 'Infrastructure as Code' blog article
--------------------------------------------------------------------------------
/iac-examples/storage.bicep:
--------------------------------------------------------------------------------
1 | param storageAccountName string
2 | param containerName string = 'logs'
3 | param location string = resourceGroup().location
4 |
5 | resource sa 'Microsoft.Storage/storageAccounts@2019-06-01' = {
6 | name: storageAccountName
7 | location: location
8 | sku: {
9 | name: 'Standard_LRS'
10 | }
11 | kind: 'StorageV2'
12 | properties: {
13 | accessTier: 'Hot'
14 | }
15 | }
16 |
17 | resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2019-06-01' = {
18 | name: '${sa.name}/default/${containerName}'
19 | }
20 |
--------------------------------------------------------------------------------
/iac-examples/storage.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3 | "contentVersion": "1.0.0.0",
4 | "metadata": {
5 | "_generator": {
6 | "name": "bicep",
7 | "version": "0.4.1008.15138",
8 | "templateHash": "8636947863337745424"
9 | }
10 | },
11 | "parameters": {
12 | "storageAccountName": {
13 | "type": "string"
14 | },
15 | "containerName": {
16 | "type": "string",
17 | "defaultValue": "logs"
18 | },
19 | "location": {
20 | "type": "string",
21 | "defaultValue": "[resourceGroup().location]"
22 | }
23 | },
24 | "functions": [],
25 | "resources": [
26 | {
27 | "type": "Microsoft.Storage/storageAccounts",
28 | "apiVersion": "2019-06-01",
29 | "name": "[parameters('storageAccountName')]",
30 | "location": "[parameters('location')]",
31 | "sku": {
32 | "name": "Standard_LRS"
33 | },
34 | "kind": "StorageV2",
35 | "properties": {
36 | "accessTier": "Hot"
37 | }
38 | },
39 | {
40 | "type": "Microsoft.Storage/storageAccounts/blobServices/containers",
41 | "apiVersion": "2019-06-01",
42 | "name": "[format('{0}/default/{1}', parameters('storageAccountName'), parameters('containerName'))]",
43 | "dependsOn": [
44 | "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
45 | ]
46 | }
47 | ]
48 | }
--------------------------------------------------------------------------------
/iac-examples/storage.tf:
--------------------------------------------------------------------------------
1 | resource "azurerm_storage_account" "storage_acount" {
2 | name = "storageAccountName"
3 | resource_group_name = azurerm_resource_group.example.name
4 | location = azurerm_resource_group.example.location
5 | account_tier = "Standard"
6 | account_replication_type = "LRS"
7 | }
8 |
9 | resource "azurerm_storage_container" "storage_account_container" {
10 | name = "logs"
11 | storage_account_name = azurerm_storage_account.example.name
12 | container_access_type = "private"
13 | }
--------------------------------------------------------------------------------
/iac-examples/storage_pulumi.py:
--------------------------------------------------------------------------------
1 | import pulumi
2 | import pulumi_azure as azure
3 |
4 | storage_acount = azure.storage.Account("storageAcount",
5 | resource_group_name=azurerm_resource_group["example"]["name"],
6 | location=azurerm_resource_group["example"]["location"],
7 | account_tier="Standard",
8 | account_replication_type="LRS")
9 | storage_account_container = azure.storage.Container("storageAccountContainer",
10 | storage_account_name=azurerm_storage_account["example"]["name"],
11 | container_access_type="private")
--------------------------------------------------------------------------------
/terraform-best-practices/README.md:
--------------------------------------------------------------------------------
1 | # Terraform Best Practices Examples
2 | This repository includes some example Terraform configurations that are referenced in this [Terraform Best Practices](https://spacelift.io/blog/terraform-best-practices) blog post.
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/production/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "3.63.0"
6 | }
7 | }
8 | }
9 |
10 | provider "aws" {
11 | region = var.aws_region
12 | }
13 |
14 | module "vpc" {
15 | source = "../../modules/vpc"
16 |
17 | vpc_name = var.vpc_name
18 | vpc_cidr = var.vpc_cidr
19 | azs = var.azs
20 | vpc_public_subnets = var.vpc_public_subnets
21 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/production/outputs.tf:
--------------------------------------------------------------------------------
1 | output "vpc_id" {
2 | description = "ID of the VPC"
3 | value = module.vpc.vpc_id
4 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/production/terraform.tfvars:
--------------------------------------------------------------------------------
1 | aws_region = "us-east-1"
2 | vpc_name = "production"
3 | vpc_cidr = "172.31.0.0/16"
4 | azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
5 | vpc_public_subnets = ["172.31.0.0/22", "172.31.4.0/22", "172.31.8.0/22"]
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/production/variables.tf:
--------------------------------------------------------------------------------
1 | variable "aws_region" {
2 | description = "AWS region"
3 | type = string
4 | }
5 |
6 | variable "vpc_name" {
7 | description = "Name for the VPC"
8 | type = string
9 | }
10 |
11 | variable "vpc_cidr" {
12 | description = "Default value for VPC CIDR"
13 | type = string
14 | default = "172.31.0.0/16"
15 | }
16 |
17 | variable "azs" {
18 | description = "Availability zones for the region"
19 | type = list(string)
20 | default = []
21 | }
22 |
23 | variable "vpc_public_subnets" {
24 | description = "Public subnets for the VPC"
25 | type = list(string)
26 | default = []
27 | }
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/staging/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "3.63.0"
6 | }
7 | }
8 | }
9 |
10 | provider "aws" {
11 | region = var.aws_region
12 | }
13 |
14 | module "vpc" {
15 | source = "../../modules/vpc"
16 |
17 | vpc_name = var.vpc_name
18 | vpc_cidr = var.vpc_cidr
19 | azs = var.azs
20 | vpc_public_subnets = var.vpc_public_subnets
21 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/staging/outputs.tf:
--------------------------------------------------------------------------------
1 | output "vpc_id" {
2 | description = "ID of the VPC"
3 | value = module.vpc.vpc_id
4 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/staging/terraform.tfvars:
--------------------------------------------------------------------------------
1 | aws_region = "us-east-2"
2 | vpc_name = "staging"
3 | vpc_cidr = "10.0.0.0/16"
4 | azs = ["us-east-2a", "us-east-2b", "us-east-2c"]
5 | vpc_public_subnets = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/staging/variables.tf:
--------------------------------------------------------------------------------
1 | variable "aws_region" {
2 | description = "AWS region"
3 | type = string
4 | }
5 |
6 | variable "vpc_name" {
7 | description = "Name for the VPC"
8 | type = string
9 | }
10 |
11 | variable "vpc_cidr" {
12 | description = "Default value for VPC CIDR"
13 | type = string
14 | default = "172.31.0.0/16"
15 | }
16 |
17 | variable "azs" {
18 | description = "Availability zones for the region"
19 | type = list(string)
20 | default = []
21 | }
22 |
23 | variable "vpc_public_subnets" {
24 | description = "Public subnets for the VPC"
25 | type = list(string)
26 | default = []
27 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/test/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "3.63.0"
6 | }
7 | }
8 | }
9 |
10 | provider "aws" {
11 | region = var.aws_region
12 | }
13 |
14 | module "vpc" {
15 | source = "../../modules/vpc"
16 |
17 | vpc_name = var.vpc_name
18 | vpc_cidr = var.vpc_cidr
19 | azs = var.azs
20 | vpc_public_subnets = var.vpc_public_subnets
21 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/test/outputs.tf:
--------------------------------------------------------------------------------
1 | output "vpc_id" {
2 | description = "ID of the VPC"
3 | value = module.vpc.vpc_id
4 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/test/terraform.tfvars:
--------------------------------------------------------------------------------
1 | aws_region = "eu-central-1"
2 | vpc_name = "test"
3 | vpc_cidr = "10.1.0.0/16"
4 | azs = ["eu-central-1a", "eu-central-1b", "eu-central-1c"]
5 | vpc_public_subnets = ["10.1.0.0/24", "10.1.1.0/24", "10.1.2.0/24"]
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/environment/test/variables.tf:
--------------------------------------------------------------------------------
1 | variable "aws_region" {
2 | description = "AWS region"
3 | type = string
4 | }
5 |
6 | variable "vpc_name" {
7 | description = "Name for the VPC"
8 | type = string
9 | }
10 |
11 | variable "vpc_cidr" {
12 | description = "Default value for VPC CIDR"
13 | type = string
14 | default = "172.31.0.0/16"
15 | }
16 |
17 | variable "azs" {
18 | description = "Availability zones for the region"
19 | type = list(string)
20 | default = []
21 | }
22 |
23 | variable "vpc_public_subnets" {
24 | description = "Public subnets for the VPC"
25 | type = list(string)
26 | default = []
27 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/modules/vpc/main.tf:
--------------------------------------------------------------------------------
1 | module "vpc" {
2 | source = "terraform-aws-modules/vpc/aws"
3 | version = "3.14"
4 |
5 | name = var.vpc_name
6 | cidr = var.vpc_cidr
7 | azs = var.azs
8 | public_subnets = var.vpc_public_subnets
9 |
10 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/modules/vpc/outputs.tf:
--------------------------------------------------------------------------------
1 | output "vpc_id" {
2 | description = "ID of the VPC"
3 | value = module.vpc.vpc_id
4 | }
--------------------------------------------------------------------------------
/terraform-best-practices/separate-environments-project-structure/modules/vpc/varariables.tf:
--------------------------------------------------------------------------------
1 | variable "vpc_name" {
2 | description = "Name for the VPC"
3 | type = string
4 | }
5 |
6 | variable "vpc_cidr" {
7 | description = "Default value for VPC CIDR"
8 | type = string
9 | default = "172.31.0.0/16"
10 | }
11 |
12 | variable "azs" {
13 | description = "Availability zones for the region"
14 | type = list(string)
15 | default = []
16 | }
17 |
18 | variable "vpc_public_subnets" {
19 | description = "Public subnets for the VPC"
20 | type = list(string)
21 | default = []
22 | }
--------------------------------------------------------------------------------
/terraform-best-practices/small-terraform-project-structure/README.md:
--------------------------------------------------------------------------------
1 | This file should contain information about your project. Be clear about the intentions and functionality of it. Include information about how to interact, use, or contribute to the project.
--------------------------------------------------------------------------------
/terraform-best-practices/small-terraform-project-structure/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "3.16.0"
6 | }
7 | }
8 | }
9 |
10 | provider "aws" {
11 | region = var.aws_region
12 | }
13 |
14 | data "aws_caller_identity" "current" {}
15 |
16 | locals {
17 | account_id = data.aws_caller_identity.current.account_id
18 | environment = "Stage"
19 | team_name = "Infrastructure"
20 | service_name = "Blue"
21 | }
22 |
23 | locals {
24 | default_tags = {
25 | Environment = local.environment
26 | Team = local.team_name
27 | Service = local.service_name
28 | }
29 | }
30 |
31 | resource "aws_vpc" "this" {
32 | cidr_block = var.vpc_cidr
33 | instance_tenancy = var.instance_tenancy
34 |
35 | tags = local.default_tags
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/terraform-best-practices/small-terraform-project-structure/outputs.tf:
--------------------------------------------------------------------------------
1 | output "vpc_id" {
2 | description = "ID of the VPC"
3 | value = aws_vpc.this.id
4 | }
--------------------------------------------------------------------------------
/terraform-best-practices/small-terraform-project-structure/terraform.tfvars:
--------------------------------------------------------------------------------
1 | aws_region = "us-east-1"
2 | vpc_cidr = "10.0.0.0/16"
--------------------------------------------------------------------------------
/terraform-best-practices/small-terraform-project-structure/variables.tf:
--------------------------------------------------------------------------------
1 | variable "aws_region" {
2 | description = "AWS region"
3 | type = string
4 | }
5 |
6 | variable "vpc_cidr" {
7 | description = "Default value for VPC CIDR"
8 | type = string
9 | default = "172.31.0.0/16"
10 | }
11 |
12 | variable "instance_tenancy" {
13 | description = "Tenancy for ec2 instances"
14 | type = string
15 | default = "default"
16 | }
--------------------------------------------------------------------------------
/terraform-github-actions/.github/workflows/terraform.yml:
--------------------------------------------------------------------------------
1 | name: "Terraform Infrastructure Change Management Pipeline with GitHub Actions"
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths:
8 | - terraform/**
9 | pull_request:
10 | branches:
11 | - main
12 | paths:
13 | - terraform/**
14 |
15 | env:
16 | TF_LOG: INFO
17 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
18 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
19 | BUCKET_TF_STATE: ${{ secrets.BUCKET_TF_STATE}}
20 |
21 | jobs:
22 | terraform:
23 | name: "Terraform Infrastructure Change Management"
24 | runs-on: ubuntu-latest
25 | defaults:
26 | run:
27 | shell: bash
28 | # We keep Terraform files in the terraform directory.
29 | working-directory: ./terraform
30 |
31 | steps:
32 | - name: Checkout the repository to the runner
33 | uses: actions/checkout@v2
34 |
35 | - name: Setup Terraform with specified version on the runner
36 | uses: hashicorp/setup-terraform@v2
37 | with:
38 | terraform_version: 1.3.0
39 |
40 | - name: Terraform init
41 | id: init
42 | run: terraform init -backend-config="bucket=$BUCKET_TF_STATE"
43 |
44 | - name: Terraform format
45 | id: fmt
46 | run: terraform fmt -check
47 |
48 | - name: Terraform validate
49 | id: validate
50 | run: terraform validate
51 |
52 | - name: Terraform plan
53 | id: plan
54 | if: github.event_name == 'pull_request'
55 | run: terraform plan -no-color -input=false
56 | continue-on-error: true
57 |
58 | - uses: actions/github-script@v6
59 | if: github.event_name == 'pull_request'
60 | env:
61 | PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
62 | with:
63 | github-token: ${{ secrets.GITHUB_TOKEN }}
64 | script: |
65 | const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
66 | #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
67 | #### Terraform Validation 🤖\`${{ steps.validate.outcome }}\`
68 | #### Terraform Plan 📖\`${{ steps.plan.outcome }}\`
69 |
70 | Show Plan
71 |
72 | \`\`\`\n
73 | ${process.env.PLAN}
74 | \`\`\`
75 |
76 |
77 | *Pushed by: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
78 |
79 | github.rest.issues.createComment({
80 | issue_number: context.issue.number,
81 | owner: context.repo.owner,
82 | repo: context.repo.repo,
83 | body: output
84 | })
85 |
86 | - name: Terraform Plan Status
87 | if: steps.plan.outcome == 'failure'
88 | run: exit 1
89 |
90 | - name: Terraform Apply
91 | if: github.ref == 'refs/heads/main' && github.event_name == 'push'
92 | run: terraform apply -auto-approve -input=false
93 |
--------------------------------------------------------------------------------
/terraform-github-actions/README.md:
--------------------------------------------------------------------------------
1 | # Manage Infrastrucutre with Terraform and GitHub Actions
2 | This demo shows an example of a GitHub Actions pipeline to manage the Terraform infrastructure lifecycle.
--------------------------------------------------------------------------------
/terraform-github-actions/terraform/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | }
6 | }
7 |
8 | backend "s3" {
9 | region = "us-west-2"
10 | key = "terraform.tfstate"
11 | }
12 | }
13 |
14 | provider "aws" {
15 | region = "us-west-2"
16 | }
17 |
18 | resource "aws_instance" "test_instance" {
19 | ami = "ami-830c94e3"
20 | instance_type = "t2.nano"
21 | tags = {
22 | Name = "test_instance"
23 | }
24 | }
--------------------------------------------------------------------------------
/terraform-output/README.md:
--------------------------------------------------------------------------------
1 | # Terraform Ouputs
2 | This repository includes all the files related to the [Terraform Outputs](https://spacelift.io/blog/terraform-output) blog post. If you want to run the examples on this repo you need [Terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli) installed and an [AWS account](https://aws.amazon.com/console/).
--------------------------------------------------------------------------------
/terraform-output/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "3.16.0"
6 | }
7 | }
8 | }
9 |
10 | provider "aws" {
11 | region = var.aws_region
12 | }
13 |
14 | module "aws_web_server_vpc" {
15 | source = "./modules/aws-web-server-vpc"
16 | }
17 |
18 | module "aws_web_server_instance" {
19 | source = "./modules/aws-web-server-instance"
20 | ec2_instance_type = var.ec2_instance_type
21 | vpc_id = module.aws_web_server_vpc.vpc_id
22 | subnet_id = module.aws_web_server_vpc.subnet_id
23 | }
--------------------------------------------------------------------------------
/terraform-output/modules/aws-web-server-instance/main.tf:
--------------------------------------------------------------------------------
1 | data "aws_ami" "amazon_linux" {
2 | most_recent = true
3 | owners = ["amazon"]
4 | filter {
5 | name = "name"
6 | values = ["amzn2-ami-hvm-*-x86_64-gp2"]
7 | }
8 | }
9 |
10 | resource "aws_security_group" "web_server" {
11 | name = var.ec2_security_group_name
12 | description = var.ec2_security_group_description
13 | vpc_id = var.vpc_id
14 |
15 | ingress {
16 | description = "Allow traffic on port 80 from everywhere"
17 | from_port = 80
18 | to_port = 80
19 | protocol = "tcp"
20 | cidr_blocks = ["0.0.0.0/0"]
21 | ipv6_cidr_blocks = ["::/0"]
22 | }
23 |
24 | egress {
25 | from_port = 0
26 | to_port = 0
27 | protocol = "-1"
28 | cidr_blocks = ["0.0.0.0/0"]
29 | ipv6_cidr_blocks = ["::/0"]
30 | }
31 |
32 | tags = {
33 | Name = var.ec2_security_group_name
34 | }
35 | }
36 |
37 | resource "aws_instance" "web_server" {
38 | ami = data.aws_ami.amazon_linux.id
39 | instance_type = var.ec2_instance_type
40 |
41 | subnet_id = var.subnet_id
42 | vpc_security_group_ids = [aws_security_group.web_server.id]
43 |
44 | tags = {
45 | Name = var.ec2_instance_name
46 | }
47 |
48 | user_data = <<-EOF
49 | #!/bin/bash
50 | sudo yum update -y
51 | sudo yum install httpd -y
52 | sudo systemctl enable httpd
53 | sudo systemctl start httpd
54 | echo "This is a test webserver!
" > /var/www/html/index.html
55 | EOF
56 | }
57 |
--------------------------------------------------------------------------------
/terraform-output/modules/aws-web-server-instance/outputs.tf:
--------------------------------------------------------------------------------
1 | output "instance_id" {
2 | description = "ID of EC2 instance"
3 | value = aws_instance.web_server.id
4 | }
5 |
6 | output "instance_public_ip" {
7 | description = "Public IP of EC2 instance"
8 | value = aws_instance.web_server.public_ip
9 | }
10 |
--------------------------------------------------------------------------------
/terraform-output/modules/aws-web-server-instance/variables.tf:
--------------------------------------------------------------------------------
1 | variable "ec2_instance_name" {
2 | description = "Name for web server EC2 instance"
3 | type = string
4 | default = "web_server"
5 | }
6 |
7 | variable "ec2_instance_type" {
8 | description = "Instance type for web server EC2 instance"
9 | type = string
10 | default = "t2.micro"
11 | }
12 |
13 | variable "ec2_security_group_name" {
14 | description = "Security group name for web server EC2 instance"
15 | type = string
16 | default = "web_server"
17 |
18 | }
19 |
20 | variable "ec2_security_group_description" {
21 | description = "Security group description for web server EC2 instance"
22 | type = string
23 | default = "Allow traffic for webserver"
24 | }
25 |
26 | variable "vpc_id" {
27 | description = "VPC id for web server EC2 instance"
28 | type = string
29 | }
30 |
31 | variable "subnet_id" {
32 | description = "Subnet id for web server EC2 instance"
33 | type = string
34 | }
35 |
--------------------------------------------------------------------------------
/terraform-output/modules/aws-web-server-vpc/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_vpc" "web_server" {
2 | cidr_block = var.vpc_cidr_block
3 | instance_tenancy = "default"
4 |
5 | tags = {
6 | Name = var.vpc_name
7 | }
8 | }
9 |
10 | resource "aws_subnet" "web_server" {
11 | vpc_id = aws_vpc.web_server.id
12 | cidr_block = var.subnet_cidr_block
13 | map_public_ip_on_launch = true
14 | availability_zone = var.aws_az
15 |
16 | tags = {
17 | Name = var.subnet_name
18 | }
19 | }
20 |
21 | resource "aws_internet_gateway" "web_server" {
22 | vpc_id = aws_vpc.web_server.id
23 |
24 | tags = {
25 | Name = var.igw_name
26 | }
27 | }
28 |
29 | resource "aws_route_table" "web_server" {
30 | vpc_id = aws_vpc.web_server.id
31 | route {
32 | cidr_block = "0.0.0.0/0"
33 | gateway_id = aws_internet_gateway.web_server.id
34 | }
35 |
36 | tags = {
37 | Name = var.rt_name
38 | }
39 | }
40 |
41 | resource "aws_route_table_association" "web_server" {
42 | subnet_id = aws_subnet.web_server.id
43 | route_table_id = aws_route_table.web_server.id
44 | }
--------------------------------------------------------------------------------
/terraform-output/modules/aws-web-server-vpc/outputs.tf:
--------------------------------------------------------------------------------
1 | output "vpc_id" {
2 | description = "ID of the VPC"
3 | value = aws_vpc.web_server.id
4 | }
5 |
6 | output "subnet_id" {
7 | description = "ID of the VPC subnet"
8 | value = aws_subnet.web_server.id
9 | }
--------------------------------------------------------------------------------
/terraform-output/modules/aws-web-server-vpc/variables.tf:
--------------------------------------------------------------------------------
1 | variable "vpc_cidr_block" {
2 | description = "CIDR block for webserver VPC"
3 | type = string
4 | default = "10.0.0.0/16"
5 | }
6 |
7 | variable "vpc_name" {
8 | description = "Name of the vpc"
9 | type = string
10 | default = "web_server"
11 | }
12 |
13 | variable "subnet_cidr_block" {
14 | description = "CIDR block for the webserver subnet"
15 | type = string
16 | default = "10.0.0.0/24"
17 | }
18 |
19 | variable "subnet_name" {
20 | description = "Name for the webserver subnet"
21 | type = string
22 | default = "web_server"
23 | }
24 |
25 | variable "aws_az" {
26 | description = "Availability Zone for the webserver subnet"
27 | type = string
28 | default = "us-east-1a"
29 | }
30 |
31 | variable "igw_name" {
32 | description = "Name for the Internet Gateway of the webserver vpc"
33 | type = string
34 | default = "web_server"
35 | }
36 |
37 | variable "rt_name" {
38 | description = "Name for the route table of the webserver vpc"
39 | type = string
40 | default = "web_server"
41 | }
42 |
--------------------------------------------------------------------------------
/terraform-output/outputs.tf:
--------------------------------------------------------------------------------
1 | output "vpc_id" {
2 | description = "ID of the vpc"
3 | value = module.aws_web_server_vpc.vpc_id
4 | }
5 |
6 | output "instance_id" {
7 | description = "ID of EC2 instance"
8 | value = module.aws_web_server_instance.instance_id
9 | }
10 |
11 | output "instance_public_ip" {
12 | description = "Public IP of EC2 instance"
13 | value = module.aws_web_server_instance.instance_public_ip
14 | }
--------------------------------------------------------------------------------
/terraform-output/terraform.tfvars:
--------------------------------------------------------------------------------
1 | aws_region = "us-east-1"
2 | ec2_instance_type = "t2.nano"
3 |
--------------------------------------------------------------------------------
/terraform-output/variables.tf:
--------------------------------------------------------------------------------
1 | variable "aws_region" {
2 | description = "AWS region"
3 | type = string
4 | }
5 |
6 | variable "ec2_instance_type" {
7 | description = "Instance type for EC2 instances"
8 | type = string
9 | default = "t2.small"
10 | }
--------------------------------------------------------------------------------
/terraform-tfvars/dev.auto.tfvars:
--------------------------------------------------------------------------------
1 | instance_type = "t2.large"
2 |
--------------------------------------------------------------------------------
/terraform-tfvars/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "~> 3.0"
6 | }
7 | }
8 | }
9 |
10 | provider "aws" {
11 | region = "us-east-1"
12 | }
13 |
14 | //referencing ubuntu AMI
15 | data "aws_ami" "ubuntu" {
16 | most_recent = true
17 | owners = ["099720109477"] #Canonical
18 |
19 | filter {
20 | name = "name"
21 | values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
22 | }
23 |
24 | filter {
25 | name = "virtualization-type"
26 | values = ["hvm"]
27 | }
28 | }
29 |
30 | //spinning up billing server
31 | resource "aws_instance" "billing_server" {
32 | ami = data.aws_ami.ubuntu.id
33 | instance_type = var.instance_type
34 | tags = {
35 | "service" = "billing"
36 | }
37 | }
38 |
39 | module "child" {
40 | source = "./modules"
41 | instance_type = var.instance_type
42 | }
--------------------------------------------------------------------------------
/terraform-tfvars/modules/main.tf:
--------------------------------------------------------------------------------
1 | //referencing ubuntu AMI
2 | data "aws_ami" "ubuntu" {
3 | most_recent = true
4 | owners = ["099720109477"] #Canonical
5 |
6 | filter {
7 | name = "name"
8 | values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
9 | }
10 |
11 | filter {
12 | name = "virtualization-type"
13 | values = ["hvm"]
14 | }
15 | }
16 |
17 | //spinning up another billing server
18 | resource "aws_instance" "billing_server" {
19 | ami = data.aws_ami.ubuntu.id
20 | instance_type = var.instance_type
21 | tags = {
22 | "service" = "billing"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/terraform-tfvars/modules/terraform.tfvars:
--------------------------------------------------------------------------------
1 | instance_type = "t2.small"
2 |
--------------------------------------------------------------------------------
/terraform-tfvars/modules/variable.tf:
--------------------------------------------------------------------------------
1 | variable "instance_type" {
2 | type = string
3 | description = "EC2 instance type"
4 | }
5 |
--------------------------------------------------------------------------------
/terraform-tfvars/prod.tfvars:
--------------------------------------------------------------------------------
1 | instance_type = "t2.xlarge"
2 |
--------------------------------------------------------------------------------
/terraform-tfvars/variable.tf:
--------------------------------------------------------------------------------
1 | variable "instance_type" {
2 | type = string
3 | default = "t2.micro"
4 | description = "EC2 instance type"
5 | }
6 |
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/README.md:
--------------------------------------------------------------------------------
1 | # Working with Ansible Playbooks
2 | This repository includes all the files related to the [Working with Ansible Playbooks](https://spacelift.io/blog/ansible-playbooks) blog post. If you want to run the examples on this repo you can execute `vagrant up` from the top of this repository in order to spin up a local vm to target with Ansible. Requirements to follow along: [Vagrant](https://www.vagrantup.com/docs/installation) and [VirtualBox](https://www.virtualbox.org/).
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure
5 | # configures the configuration version (we support older styles for
6 | # backwards compatibility). Please don't change it unless you know what
7 | # you're doing.
8 | Vagrant.configure("2") do |config|
9 | # The most common configuration options are documented and commented below.
10 | # For a complete reference, please see the online documentation at
11 | # https://docs.vagrantup.com.
12 |
13 | # Every Vagrant development environment requires a box. You can search for
14 | # boxes at https://vagrantcloud.com/search.
15 |
16 | config.vm.define "host1" do |host1|
17 | host1.vm.box = "hashicorp/bionic64"
18 | end
19 |
20 | config.vm.define "host2" do |host2|
21 | host2.vm.box = "hashicorp/bionic64"
22 | end
23 |
24 | # Disable automatic box update checking. If you disable this, then
25 | # boxes will only be checked for updates when the user runs
26 | # `vagrant box outdated`. This is not recommended.
27 | # config.vm.box_check_update = false
28 |
29 | # Create a forwarded port mapping which allows access to a specific port
30 | # within the machine from a port on the host machine. In the example below,
31 | # accessing "localhost:8080" will access port 80 on the guest machine.
32 | # NOTE: This will enable public access to the opened port
33 | # config.vm.network "forwarded_port", guest: 80, host: 8080
34 |
35 | # Create a forwarded port mapping which allows access to a specific port
36 | # within the machine from a port on the host machine and only allow access
37 | # via 127.0.0.1 to disable public access
38 | # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
39 |
40 | # Create a private network, which allows host-only access to the machine
41 | # using a specific IP.
42 | # config.vm.network "private_network", ip: "192.168.33.10"
43 |
44 | # Create a public network, which generally matched to bridged network.
45 | # Bridged networks make the machine appear as another physical device on
46 | # your network.
47 | # config.vm.network "public_network"
48 |
49 | # Share an additional folder to the guest VM. The first argument is
50 | # the path on the host to the actual folder. The second argument is
51 | # the path on the guest to mount the folder. And the optional third
52 | # argument is a set of non-required options.
53 | # config.vm.synced_folder "../data", "/vagrant_data"
54 |
55 | # Provider-specific configuration so you can fine-tune various
56 | # backing providers for Vagrant. These expose provider-specific options.
57 | # Example for VirtualBox:
58 | #
59 | # config.vm.provider "virtualbox" do |vb|
60 | # # Display the VirtualBox GUI when booting the machine
61 | # vb.gui = true
62 | #
63 | # # Customize the amount of memory on the VM:
64 | # vb.memory = "1024"
65 | # end
66 | #
67 | # View the documentation for the provider you are using for more
68 | # information on available options.
69 |
70 | # Enable provisioning with a shell script. Additional provisioners such as
71 | # Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
72 | # documentation for more information about their specific syntax and use.
73 | # config.vm.provision "shell", inline: <<-SHELL
74 | # apt-get update
75 | # apt-get install -y apache2
76 | # SHELL
77 | end
78 |
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/ansible.cfg:
--------------------------------------------------------------------------------
1 | [defaults]
2 | inventory=./hosts
3 | deprecation_warnings=False
4 | nocows = 1
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/example-conditionals-playbook.yml:
--------------------------------------------------------------------------------
1 | - name: Example Simple Conditional
2 | hosts: all
3 | vars:
4 | trigger_task: true
5 |
6 | tasks:
7 | - name: Install nginx
8 | apt:
9 | name: "nginx"
10 | state: present
11 | when: trigger_task
12 |
13 | - name: Example Facts Conditionals
14 | hosts: all
15 | vars:
16 | supported_os:
17 | - RedHat
18 | - Fedora
19 |
20 | tasks:
21 | - name: Install nginx
22 | yum:
23 | name: "nginx"
24 | state: present
25 | when: ansible_facts['distribution'] in supported_os
26 |
27 | - name: Example Registered Variables Conditionals
28 | hosts: all
29 |
30 | tasks:
31 | - name: Register an example variable
32 | ansible.builtin.shell: cat /etc/hosts
33 | register: hosts_contents
34 |
35 | - name: Check if hosts file contains "localhost"
36 | ansible.builtin.shell: echo "/etc/hosts contains localhost"
37 | when: hosts_contents.stdout.find(localhost) != -1
38 |
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/example-handlers-playbook.yml:
--------------------------------------------------------------------------------
1 |
2 | - name: Example with handler - Update apache config
3 | hosts: webservers
4 |
5 | tasks:
6 | - name: Write the apache config file
7 | ansible.builtin.template:
8 | src: /srv/httpd.j2
9 | dest: /etc/httpd.conf
10 | notify:
11 | - Restart apache
12 |
13 | handlers:
14 | - name: Restart apache
15 | ansible.builtin.service:
16 | name: httpd
17 | state: restarted
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/example-loops-playbook.yml:
--------------------------------------------------------------------------------
1 | - name: Examples with Loops
2 | hosts: all
3 |
4 | tasks:
5 | - name: "Create some files"
6 | ansible.builtin.file:
7 | state: touch
8 | path: /tmp/{{ item }}
9 | loop:
10 | - example_file1
11 | - example_file2
12 | - example_file3
13 |
14 | - name: "Create some files with dictionaries"
15 | ansible.builtin.file:
16 | state: touch
17 | path: "/tmp/{{ item.filename }}"
18 | mode: "{{ item.mode }}"
19 | loop:
20 | - { filename: 'example_file1', mode: '755'}
21 | - { filename: 'example_file2', mode: '775'}
22 | - { filename: 'example_file3', mode: '777'}
23 |
24 | - name: Show all the hosts in the inventory
25 | ansible.builtin.debug:
26 | msg: "{{ item }}"
27 | loop: "{{ groups['databases'] }}"
28 |
29 | - name: Execute when values in list are lower than 10
30 | ansible.builtin.command: echo {{ item }}
31 | loop: [ 100, 200, 3, 600, 7, 11 ]
32 | when: item < 10
33 |
34 |
35 | - name: Retry a task until we find the word “success” in the logs
36 | shell: cat /var/log/example_log
37 | register: result
38 | until: result.stdout.find("success") != -1
39 | retries: 10
40 | delay: 15
41 |
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/example-secrets-playbook.yml:
--------------------------------------------------------------------------------
1 | - name: Example decrypt Ansible Vault variable
2 | hosts: all
3 | vars:
4 | db_password: !vault |
5 | $ANSIBLE_VAULT;1.1;AES256
6 | 64613161626261666130396330323463333336663363613065346330643138346335346563633837
7 | 3234373132313362636263666538383436633332323034620a656333396639383532366634333764
8 | 39396233303164353763386430343836373938643831613365366366333335386633633936373035
9 | 3832363735643032630a343439396632363536633439393762343965636163343061383735333963
10 | 3435
11 |
12 | tasks:
13 | - name: Use the db_password value
14 | debug:
15 | msg: "This is a test to validate that we can decrypt correctly the example encrypted variable db_password: {{db_password}} "
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/example-simple-playbook.yml:
--------------------------------------------------------------------------------
1 | - name: Example Simple Playbook
2 | hosts: all
3 | become: yes
4 |
5 | tasks:
6 | - name: Copy file example_file to /tmp with permissions
7 | ansible.builtin.copy:
8 | src: ./example_file
9 | dest: /tmp/example_file
10 | mode: '0644'
11 |
12 | - name: Add the user 'bob' with a specific uid
13 | ansible.builtin.user:
14 | name: bob
15 | state: present
16 | uid: 1040
17 |
18 | - name: Update postgres servers
19 | hosts: databases
20 | become: yes
21 |
22 | tasks:
23 | - name: Ensure postgres DB is at the latest version
24 | ansible.builtin.yum:
25 | name: postgresql
26 | state: latest
27 |
28 | - name: Ensure that postgresql is started
29 | ansible.builtin.service:
30 | name: postgresql
31 | state: started
32 |
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/example-variables-2-playbook.yml:
--------------------------------------------------------------------------------
1 | - name: Example-2 Variables Playbook
2 | hosts: all
3 |
4 | tasks:
5 | - name: Run a script and register the output as a variable
6 | shell: "find example_file"
7 | args:
8 | chdir: "/tmp"
9 | register: example_script_output
10 | - name: Use the output variable of the previous task
11 | debug:
12 | var: example_script_output
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/example-variables-playbook.yml:
--------------------------------------------------------------------------------
1 | - name: Example Variables Playbook
2 | hosts: all
3 | vars:
4 | username: bob
5 |
6 | tasks:
7 | - name: Add the user {{ username }}
8 | ansible.builtin.user:
9 | name: "{{ username }}"
10 | state: present
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/example_file:
--------------------------------------------------------------------------------
1 | This is an example
--------------------------------------------------------------------------------
/working-with-ansible-playbooks/hosts:
--------------------------------------------------------------------------------
1 | host1 ansible_host=127.0.0.1 ansible_user=vagrant ansible_port=2201 ansible_ssh_private_key_file=./.vagrant/machines/host1/virtualbox/private_key
--------------------------------------------------------------------------------