If you are responsible for managing a bunch of your organization’s AWS
resources, you probably know how annoying it is to debug various
deployment-related issues, only to learn that someone accidentally messed with
your setup, yet again. Which you probably resolved by navigating your
command-line history like a maniac (because you don’t use Ansible and have to
Ctrl+R
, as you also forgot to put down the setup instructions ;)). We’ve
been there, too. And this is what we learned:
- You should use Ansible and deploy your environment with a playbook, and
- You should make the most of it by taking advantage of both Ansible’s built-in mechanisms and the modules that allow you to detect configuration drift, and correct it.
Our dear sysadmins and DevOps engineers, this post is for you. Stay with us and read along!
Ansible and compliance? How?
According to Cambridge Advanced Learner’s Dictionary, compliance is
The fact of obeying a particular law or rule, or of acting according to an agreement.
To see what the above definition has got to do with Ansible and the AWS Ansible Collection, let’s briefly descend to the world of Ansible playbooks and modules.
It’s all about state
Ideally, playbook tasks describe the desired final state of a managed system - for example, configuration of an AWS EC2 instance. An Ansible module takes that description and performs the necessary steps to ensure that state.
It’s important to emphasize that it’s easy to write playbook tasks describing the final state of a managed system when Ansible modules adopt declarative APIs. As a consequence, we can treat playbook tasks as “the rule”, “the policy”, or simply as something we need to be compliant with. Perhaps even more importantly, we can treat Ansible playbooks as simple diagnostic tools to help us detect when we are not compliant anymore, so that we can mitigate the situation.
If you are familiar with Ansible, all of this probably rings a bell to you
already. Was your first thought the value of the changed
variable that you
see every time you run your playbooks? Or perhaps even Ansible’s
--diff
and --check
modes? Indeed, this post is about all of
them!
Let’s walk through a practical example demonstrating how you can use the modules from the AWS Ansible Collection to detect and resolve configuration drift.
To follow along easier, make sure you have completed the tutorial about the basic usage of the collection in Getting Started with the AWS Ansible Collection.
Make sure you have Steampunk AWS Ansible Collection version 0.8.3 installed.
Set up the desired state
Let’s start by creating a simple AWS enviromnent that will support running an imaginary app. The environment will comprise:
- an EC2 instance named steamy-server;
- a network interface named steamy-eni to attach to the EC2 instance, which we secure with the VPC’s default security group.
We created a playbook called setup.yaml for spinning up this environment. And then, we run
$ ansible-playbook setup.yaml --diff
Output:
PLAY [localhost] ************************************************************
TASK [Create the steamy-server instance for running a simple app] ***********
--- before
categories:
- tech
--- before
+++ after
+++ after
@@ -1 +1,24 @@
@@ -1 +1,24 @@
-{}
-{}
+{
+{
+ "ami": "ami-085925f297f89fce1",
+ "ami": "ami-085925f297f89fce1",
+ "availability_zone": "use1-az1",
+ "availability_zone": "use1-az1",
+ "id": "i-0f1300d2456233353",
+ "id": "i-0f1300d2456233353",
+ "key_pair": "test-keypair",
+ "key_pair": "test-keypair",
+ "launched_at": "2020-06-12T07:35:19+00:00",
+ "launched_at": "2020-06-12T07:35:19+00:00",
+ "monitoring": "detailed",
+ "monitoring": "detailed",
+ "network_interface": "eni-0cf22a025bd9f7c98",
+ "network_interface": "eni-0cf22a025bd9f7c98",
+ "on_instance_initiated_shutdown": "stop",
+ "on_instance_initiated_shutdown": "stop",
+ "secondary_network_interfaces": [],
+ "secondary_network_interfaces": [],
+ "security_groups": [
+ "security_groups": [
+ "sg-0415ac333af261fc1"
+ "sg-0415ac333af261fc1"
+ ],
+ ],
+ "state": "running",
+ "state": "running",
+ "subnet": "subnet-06a0f705bc79538ed",
+ "subnet": "subnet-06a0f705bc79538ed",
+ "tags": {
+ "tags": {
+ "Name": "steamy-server",
+ "Name": "steamy-server",
+ "app": "steamy",
+ "app": "steamy",
+ "env": "staging"
+ "env": "staging"
+ },
+ },
+ "tenancy": "default",
+ "tenancy": "default",
+ "type": "t3.micro",
+ "type": "t3.micro",
+ "vpc": "vpc-032c4ec6c40cf17a3"
+ "vpc": "vpc-032c4ec6c40cf17a3"
+}
+}
changed: [localhost]
changed: [localhost]
TASK [Retrieve the default security group for the VPC] **********************
TASK [Retrieve the default security group for the VPC] **********************
ok: [localhost]
ok: [localhost]
TASK [Create a dedicated network interface and attach it to steamy-server] **
TASK [Create a dedicated network interface and attach it to steamy-server] **
--- before
categories:
- tech
--- before
+++ after
+++ after
@@ -1 +1,21 @@
@@ -1 +1,21 @@
-{}
-{}
+{
+{
+ "attachment": {
+ "attachment": {
+ "device_index": 1,
+ "device_index": 1,
+ "instance": "i-0f1300d2456233353",
+ "instance": "i-0f1300d2456233353",
+ "keep_on_termination": false
+ "keep_on_termination": false
+ },
+ },
+ "description": null,
+ "description": null,
+ "id": "eni-0c7d09f8e5290b78d",
+ "id": "eni-0c7d09f8e5290b78d",
+ "ip": "172.31.6.213",
+ "ip": "172.31.6.213",
+ "mac_address": "02:5b:f9:a2:db:fd",
+ "mac_address": "02:5b:f9:a2:db:fd",
+ "public_ip": null,
+ "public_ip": null,
+ "security_groups": [
+ "security_groups": [
+ "sg-0415ac333af261fc1"
+ "sg-0415ac333af261fc1"
+ ],
+ ],
+ "source_dest_check": true,
+ "source_dest_check": true,
+ "subnet": "subnet-06a0f705bc79538ed",
+ "subnet": "subnet-06a0f705bc79538ed",
+ "tags": {
+ "tags": {
+ "Name": "steamy-eni"
+ "Name": "steamy-eni"
+ },
+ },
+ "type": "normal"
+ "type": "normal"
+}
+}
changed: [localhost]
changed: [localhost]
PLAY RECAP ******************************************************************
PLAY RECAP ******************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0
localhost : ok=3 changed=2 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
skipped=0 rescued=0 ignored=0
We can see two `changed` tasks, corresponding to the two newly created AWS
We can see two `changed` tasks, corresponding to the two newly created AWS
resources. Thanks to the `--diff` flag which instructs the modules to report
resources. Thanks to the `--diff` flag which instructs the modules to report
the differences they made, we also get a nice visual indication of what
the differences they made, we also get a nice visual indication of what
exactly the modules changed. The red-colored lines show the previous state of
exactly the modules changed. The red-colored lines show the previous state of
the AWS resource (before a specific task ran), while the green ones show the
the AWS resource (before a specific task ran), while the green ones show the
current state, i.e. after the task ran.
current state, i.e. after the task ran.
We can interpret the diff output above as "the instance and network interface
We can interpret the diff output above as "the instance and network interface
didn't exist before, so we created them, and they are now configured as
didn't exist before, so we created them, and they are now configured as
shown".
shown".
> Typically, we can't take support for diff mode for granted, as it is up to
> Typically, we can't take support for diff mode for granted, as it is up to
> individual modules to implement it. This is why some tasks make changes but
> individual modules to implement it. This is why some tasks make changes but
> report no differences despite running `ansible-playbook` with `--diff`.
> report no differences despite running `ansible-playbook` with `--diff`.
### A word about idempotence
### A word about idempotence
Can you guess what will happen if we run the same command again? Let's try it
Can you guess what will happen if we run the same command again? Let's try it
out!
out!
$ ansible-playbook setup.yaml --diff
$ ansible-playbook setup.yaml --diff
Output:
Output:
PLAY [localhost] ************************************************************
PLAY [localhost] ************************************************************
TASK [Create the steamy-server instance for running a simple app] ***********
TASK [Create the steamy-server instance for running a simple app] ***********
ok: [localhost]
ok: [localhost]
TASK [Retrieve the default security group for the VPC] **********************
TASK [Retrieve the default security group for the VPC] **********************
ok: [localhost]
ok: [localhost]
TASK [Create a dedicated network interface and attach it to steamy-server] **
TASK [Create a dedicated network interface and attach it to steamy-server] **
ok: [localhost]
ok: [localhost]
PLAY RECAP ******************************************************************
PLAY RECAP ******************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
localhost : ok=3 changed=0 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
skipped=0 rescued=0 ignored=0
This time around, we see that there was nothing to be done - the Ansible
This time around, we see that there was nothing to be done - the Ansible
modules already did all the hard work when they were invoked the first time.
modules already did all the hard work when they were invoked the first time.
So no changed tasks, no updates done, and no diff output shown. With other
So no changed tasks, no updates done, and no diff output shown. With other
words, the current state of our managed AWS resources is compliant with the
words, the current state of our managed AWS resources is compliant with the
state described by the tasks in our `setup.yaml` playbook. This demonstrates
state described by the tasks in our `setup.yaml` playbook. This demonstrates
another important aspect related to Ansible's declarative approach, which is
another important aspect related to Ansible's declarative approach, which is
that playbook tasks should ideally be idempotent. If the state of the managed
that playbook tasks should ideally be idempotent. If the state of the managed
resource is aligned with the desired state as described by the playbook tasks,
resource is aligned with the desired state as described by the playbook tasks,
running the playbook again will not affect its state.
running the playbook again will not affect its state.
But how can all of this be useful to me, you wonder? Glad you asked, time to
But how can all of this be useful to me, you wonder? Glad you asked, time to
spice things up a bit!
spice things up a bit!
## Deviate from the initial state
## Deviate from the initial state
Now, let's put ourselves in the shoes of an adversary that wants to tweak the
Now, let's put ourselves in the shoes of an adversary that wants to tweak the
state of our AWS resources to their taste. In practice, this could be done
state of our AWS resources to their taste. In practice, this could be done
accidentally, or worse - with malicious intent. But we'll be doing it solely
accidentally, or worse - with malicious intent. But we'll be doing it solely
for the purpose of demonstration. Disclaimer: we won't actually be doing
for the purpose of demonstration. Disclaimer: we won't actually be doing
anything dangerous, we'll only make some simple configuration changes that
anything dangerous, we'll only make some simple configuration changes that
should indicate that configuration has drifted if we take [setup.yaml][setup]
should indicate that configuration has drifted if we take [setup.yaml][setup]
as our baseline for compliance.
as our baseline for compliance.
To make the changes, we could open the AWS Management Console and manually
To make the changes, we could open the AWS Management Console and manually
modify some properties of the EC2 instance or the network interface that we
modify some properties of the EC2 instance or the network interface that we
created with [setup.yaml][setup` earlier. But since we're all about
created with [setup.yaml][setup` earlier. But since we're all about
automation, let's put the tweaks in an Ansible playbook called
automation, let's put the tweaks in an Ansible playbook called
[tweaked-setup.yaml][tweaked].
[tweaked-setup.yaml][tweaked].
[tweaked]:
[tweaked]:
https://github.com/xlab-si/steampunk-aws-examples/blob/master/enforcing-compliance/tweaked-setup.yaml
https://github.com/xlab-si/steampunk-aws-examples/blob/master/enforcing-compliance/tweaked-setup.yaml
(Playbook simulating an adversary)
(Playbook simulating an adversary)
Here's a recap of what we'll be tweaking with this playbook:
Here's a recap of what we'll be tweaking with this playbook:
* We'll downgrade our _steamy-server_'s CloudWatch monitoring to the
* We'll downgrade our _steamy-server_'s CloudWatch monitoring to the
basic level and modify it's shutdown behavior;
basic level and modify it's shutdown behavior;
* We'll update the value of _steamy-server_'s `env` tag.
* We'll update the value of _steamy-server_'s `env` tag.
* We'll create a new security group called _dangerous-secgroup_ with
* We'll create a new security group called _dangerous-secgroup_ with
some suspicious permissions;
some suspicious permissions;
* We'll associate this _dangerous-secgroup_ with the network interface
* We'll associate this _dangerous-secgroup_ with the network interface
attached to the _steamy-server_ instance, and we'll also disable
attached to the _steamy-server_ instance, and we'll also disable
source/destination checking for the network interface;
source/destination checking for the network interface;
Sneaky, right? ;)
Sneaky, right? ;)
If we ran `ansible-playbook tweaked-setup.yaml` now, we would end up with
If we ran `ansible-playbook tweaked-setup.yaml` now, we would end up with
three changed tasks. But since we're learning about Ansible diff mode, let's
three changed tasks. But since we're learning about Ansible diff mode, let's
do:
do:
$ ansible-playbook tweaked-setup.yaml --diff
$ ansible-playbook tweaked-setup.yaml --diff
and we end up with three changed tasks, plus the diff output consistent with
and we end up with three changed tasks, plus the diff output consistent with
the tweaks described above:
the tweaks described above:
```diff
```diff
PLAY [localhost] ************************************************************
PLAY [localhost] ************************************************************
TASK [Retrieve the steamy-server instance] **********************************
TASK [Retrieve the steamy-server instance] **********************************
ok: [localhost]
ok: [localhost]
TASK [Modify configuration of the steamy-server instance] *******************
TASK [Modify configuration of the steamy-server instance] *******************
--- before
categories:
- tech
--- before
+++ after
+++ after
@@ -4,9 +4,9 @@
@@ -4,9 +4,9 @@
"id": "i-0f1300d2456233353",
"id": "i-0f1300d2456233353",
"key_pair": "test-keypair",
"key_pair": "test-keypair",
"launched_at": "2020-06-12T07:35:19+00:00",
"launched_at": "2020-06-12T07:35:19+00:00",
- "monitoring": "detailed",
- "monitoring": "detailed",
+ "monitoring": "basic",
+ "monitoring": "basic",
"network_interface": "eni-0cf22a025bd9f7c98",
"network_interface": "eni-0cf22a025bd9f7c98",
- "on_instance_initiated_shutdown": "stop",
- "on_instance_initiated_shutdown": "stop",
+ "on_instance_initiated_shutdown": "terminate",
+ "on_instance_initiated_shutdown": "terminate",
"secondary_network_interfaces": [
"secondary_network_interfaces": [
"eni-0c7d09f8e5290b78d"
"eni-0c7d09f8e5290b78d"
],
],
@@ -18,7 +18,7 @@
@@ -18,7 +18,7 @@
"tags": {
"tags": {
"Name": "steamy-server",
"Name": "steamy-server",
"app": "steamy",
"app": "steamy",
- "env": "staging"
- "env": "staging"
+ "env": "dev"
+ "env": "dev"
},
},
"tenancy": "default",
"tenancy": "default",
"type": "t3.micro",
"type": "t3.micro",
changed: [localhost]
changed: [localhost]
TASK [Create a security group to permit SMB traffic from anywhere] **********
TASK [Create a security group to permit SMB traffic from anywhere] **********
changed: [localhost]
changed: [localhost]
TASK [Extend steamy-eni's security groups, and update source/dest checking] *
TASK [Extend steamy-eni's security groups, and update source/dest checking] *
--- before
categories:
- tech
--- before
+++ after
+++ after
@@ -10,9 +10,10 @@
@@ -10,9 +10,10 @@
"mac_address": "02:5b:f9:a2:db:fd",
"mac_address": "02:5b:f9:a2:db:fd",
"public_ip": null,
"public_ip": null,
"security_groups": [
"security_groups": [
+ "sg-0447e7e7bc88aeab1",
+ "sg-0447e7e7bc88aeab1",
"sg-0415ac333af261fc1"
"sg-0415ac333af261fc1"
],
],
- "source_dest_check": true,
- "source_dest_check": true,
+ "source_dest_check": false,
+ "source_dest_check": false,
"subnet": "subnet-d8b640be",
"subnet": "subnet-d8b640be",
"tags": {
"tags": {
"Name": "steamy-eni"
"Name": "steamy-eni"
changed: [localhost]
changed: [localhost]
PLAY RECAP ******************************************************************
PLAY RECAP ******************************************************************
localhost : ok=4 changed=3 unreachable=0 failed=0
localhost : ok=4 changed=3 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
skipped=0 rescued=0 ignored=0
Basically, [tweaked-setup.yaml][tweaked] introduced an alternative desired
Basically, [tweaked-setup.yaml][tweaked] introduced an alternative desired
state of the AWS resources - the adversary's. And this state is not exactly in
state of the AWS resources - the adversary's. And this state is not exactly in
agreement with the one we described in [setup.yaml][setup] (we already learned
agreement with the one we described in [setup.yaml][setup] (we already learned
that if it were, the last invocation of `ansible-playbook` would report no
that if it were, the last invocation of `ansible-playbook` would report no
changed tasks!).
changed tasks!).
## Detect configuration drift
## Detect configuration drift
Let's now imagine that one day, we get a call from our teammates who report
Let's now imagine that one day, we get a call from our teammates who report
unusual traffic to the app server instance we provisioned on AWS, using our
unusual traffic to the app server instance we provisioned on AWS, using our
[setup.yaml][setup].
[setup.yaml][setup].
Luckily, we know what to do; for starters, we'll try re-running the
Luckily, we know what to do; for starters, we'll try re-running the
[setup.yaml][setup] playbook, but with one important addition: this time we'll
[setup.yaml][setup] playbook, but with one important addition: this time we'll
add the `--check` flag to the `ansible-playbook` command.
add the `--check` flag to the `ansible-playbook` command.
The `--check` flag instructs the modules behind playbook tasks to run in
The `--check` flag instructs the modules behind playbook tasks to run in
__check mode__ (also called __dry run__). In check mode, a module does not
__check mode__ (also called __dry run__). In check mode, a module does not
perform any work that would change the state of the resource it manages.
perform any work that would change the state of the resource it manages.
Instead, the module merely _checks_ whether a change would need to be made to
Instead, the module merely _checks_ whether a change would need to be made to
ensure the desired state. This is evident from the module's `changed` value,
ensure the desired state. This is evident from the module's `changed` value,
and you might already be familiar with it.
and you might already be familiar with it.
$ ansible-playbook setup.yaml --check
$ ansible-playbook setup.yaml --check
Output:
Output:
PLAY [localhost] ************************************************************
PLAY [localhost] ************************************************************
TASK [Create the steamy-server instance for running a simple app] ***********
TASK [Create the steamy-server instance for running a simple app] ***********
changed: [localhost]
changed: [localhost]
TASK [Retrieve the default security group for the VPC] **********************
TASK [Retrieve the default security group for the VPC] **********************
ok: [localhost]
ok: [localhost]
TASK [Create a dedicated network interface and attach it to steamy-server] **
TASK [Create a dedicated network interface and attach it to steamy-server] **
changed: [localhost]
changed: [localhost]
PLAY RECAP ******************************************************************
PLAY RECAP ******************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0
localhost : ok=3 changed=2 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
skipped=0 rescued=0 ignored=0
We notice something peculiar in the above output: two changed tasks. This
We notice something peculiar in the above output: two changed tasks. This
could very well be the related to the problem our teammates reported. But at
could very well be the related to the problem our teammates reported. But at
this point, it's too early to make any conclusions. We only know that
this point, it's too early to make any conclusions. We only know that
_something_ has changed on the instance and network interface with respect to
_something_ has changed on the instance and network interface with respect to
how we want them configured.
how we want them configured.
However, our goal is not only to verify that a configuration has drifted, but
However, our goal is not only to verify that a configuration has drifted, but
to pinpoint exactly what deviated from the desired state. Luckily, we have
to pinpoint exactly what deviated from the desired state. Luckily, we have
another trick up our sleeve. You guessed it, it's as simple as adding our
another trick up our sleeve. You guessed it, it's as simple as adding our
beloved `--diff` flag to the previous `ansible-playbook --check` command:
beloved `--diff` flag to the previous `ansible-playbook --check` command:
$ ansible-playbook setup.yaml --check --diff
$ ansible-playbook setup.yaml --check --diff
Output:
Output:
```diff
```diff
PLAY [localhost] ************************************************************
PLAY [localhost] ************************************************************
TASK [Create the steamy-server instance for running a simple app] ***********
TASK [Create the steamy-server instance for running a simple app] ***********
--- before
categories:
- tech
--- before
+++ after
+++ after
@@ -4,9 +4,9 @@
@@ -4,9 +4,9 @@
"id": "i-0f1300d2456233353",
"id": "i-0f1300d2456233353",
"key_pair": "test-keypair",
"key_pair": "test-keypair",
"launched_at": "2020-06-12T07:35:19+00:00",
"launched_at": "2020-06-12T07:35:19+00:00",
- "monitoring": "basic",
- "monitoring": "basic",
+ "monitoring": "detailed",
+ "monitoring": "detailed",
"network_interface": "eni-0cf22a025bd9f7c98",
"network_interface": "eni-0cf22a025bd9f7c98",
- "on_instance_initiated_shutdown": "terminate",
- "on_instance_initiated_shutdown": "terminate",
+ "on_instance_initiated_shutdown": "stop",
+ "on_instance_initiated_shutdown": "stop",
"secondary_network_interfaces": [
"secondary_network_interfaces": [
"eni-0c7d09f8e5290b78d"
"eni-0c7d09f8e5290b78d"
],
],
@@ -18,7 +18,7 @@
@@ -18,7 +18,7 @@
"tags": {
"tags": {
"Name": "steamy-server",
"Name": "steamy-server",
"app": "steamy",
"app": "steamy",
- "env": "dev"
- "env": "dev"
+ "env": "staging"
+ "env": "staging"
},
},
"tenancy": "default",
"tenancy": "default",
"type": "t3.micro",
"type": "t3.micro",
changed: [localhost]
changed: [localhost]
TASK [Retrieve the default security group for the VPC] **********************
TASK [Retrieve the default security group for the VPC] **********************
ok: [localhost]
ok: [localhost]
TASK [Create a dedicated network interface and attach it to steamy-server] **
TASK [Create a dedicated network interface and attach it to steamy-server] **
--- before
categories:
- tech
--- before
+++ after
+++ after
@@ -10,10 +10,9 @@
@@ -10,10 +10,9 @@
"mac_address": "02:5b:f9:a2:db:fd",
"mac_address": "02:5b:f9:a2:db:fd",
"public_ip": null,
"public_ip": null,
"security_groups": [
"security_groups": [
- "sg-0447e7e7bc88aeab1",
- "sg-0447e7e7bc88aeab1",
"sg-0415ac333af261fc1"
"sg-0415ac333af261fc1"
],
],
- "source_dest_check": false,
- "source_dest_check": false,
+ "source_dest_check": true,
+ "source_dest_check": true,
"subnet": "subnet-d8b640be",
"subnet": "subnet-d8b640be",
"tags": {
"tags": {
"Name": "steamy-eni"
"Name": "steamy-eni"
changed: [localhost]
changed: [localhost]
PLAY RECAP ******************************************************************
PLAY RECAP ******************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0
localhost : ok=3 changed=2 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
skipped=0 rescued=0 ignored=0
If we compare the output of this command and the output of `ansible-playbook
If we compare the output of this command and the output of `ansible-playbook
tweaked-setup.yaml --diff` that we ran earlier, we can see that they're
tweaked-setup.yaml --diff` that we ran earlier, we can see that they're
exactly the opposite. So the last `ansible-playbook` command we ran detected
exactly the opposite. So the last `ansible-playbook` command we ran detected
what `tweaked-setup.yaml` modified in our desired AWS setup. And if we we
what `tweaked-setup.yaml` modified in our desired AWS setup. And if we we
weren't running in check mode, we could actually ...
weren't running in check mode, we could actually ...
## Enforce compliance!
## Enforce compliance!
Fear not - our [setup.yaml][setup] describes the desired configuration state
Fear not - our [setup.yaml][setup] describes the desired configuration state
of our AWS resources exactly, so the modules from the AWS Ansible Collection
of our AWS resources exactly, so the modules from the AWS Ansible Collection
know what to do. To repair our setup, i.e. to bring it back to the desired
know what to do. To repair our setup, i.e. to bring it back to the desired
state, let's run `ansible-playbook` command once more, but this time without
state, let's run `ansible-playbook` command once more, but this time without
`--check`:
`--check`:
$ ansible-playbook setup.yaml --diff
$ ansible-playbook setup.yaml --diff
And we can observe exactly the same output as with the previous command. This
And we can observe exactly the same output as with the previous command. This
time however, the modules actually performed the changes shown in the diff
time however, the modules actually performed the changes shown in the diff
output.
output.
Afterwards, we can try running the same command again and we should end up
Afterwards, we can try running the same command again and we should end up
with no changed tasks, once again. This indicates that the configuration state
with no changed tasks, once again. This indicates that the configuration state
of our AWS resources is up-to-date with the configuration described in our
of our AWS resources is up-to-date with the configuration described in our
[setup.yaml][setup] playbook. And we are compliant with our baseline setup!
[setup.yaml][setup] playbook. And we are compliant with our baseline setup!
## But I get no output with my playbooks
## But I get no output with my playbooks
As we said before, not all modules support running in check mode or displaying
As we said before, not all modules support running in check mode or displaying
differences between the before and after states. Our
differences between the before and after states. Our
[AWS Ansible Collection][aws-steampunk] was designed with this use case in
[AWS Ansible Collection][aws-steampunk] was designed with this use case in
mind, so make sure you [check it out][steampunk].
mind, so make sure you [check it out][steampunk].
[aws-steampunk]: https://steampunk.si#aws-ansible
[aws-steampunk]: https://steampunk.si#aws-ansible
[steampunk]: https://steampunk.si#try-aws
[steampunk]: https://steampunk.si#try-aws
## What's next?
## What's next?
In this post we demonstrated the value of Ansible's `--diff` and `--check`
In this post we demonstrated the value of Ansible's `--diff` and `--check`
mode and how we can use the modules in the AWS Ansible Collection to detect
mode and how we can use the modules in the AWS Ansible Collection to detect
configuration drift, which makes them suitable as a tool to ensure compliance
configuration drift, which makes them suitable as a tool to ensure compliance
of the state of AWS resources. Perhaps the nicest thing in this whole story is
of the state of AWS resources. Perhaps the nicest thing in this whole story is
that we used the same playbook for setting up the infrastructure, detecting
that we used the same playbook for setting up the infrastructure, detecting
the changes, and restoring our setup back to the desired state.
the changes, and restoring our setup back to the desired state.
In our example, we ran the compliance checks using `--check --diff` after
In our example, we ran the compliance checks using `--check --diff` after
receiving an imaginary report about unusual behavior of the app running on our
receiving an imaginary report about unusual behavior of the app running on our
AWS resources. Try to imagine a similar situation, but with a real-world app
AWS resources. Try to imagine a similar situation, but with a real-world app
deployment. How many of the app's users could be affected and possibly
deployment. How many of the app's users could be affected and possibly
discouraged from interacting with the app ever again, before state alterations
discouraged from interacting with the app ever again, before state alterations
(accidental or not) were discovered, reported, and, finally, fixed? So if we
(accidental or not) were discovered, reported, and, finally, fixed? So if we
wanted to take things a bit further, we could implement automated checks that
wanted to take things a bit further, we could implement automated checks that
would periodically run `ansible-playbook setup.yaml --check --diff` command.
would periodically run `ansible-playbook setup.yaml --check --diff` command.
This way, we could increase the chances of picking up anomalies, and be
This way, we could increase the chances of picking up anomalies, and be
notified of similar situations before anyone notices.
notified of similar situations before anyone notices.
If you have any questions, troubles, or doubts, you can always reach us on
If you have any questions, troubles, or doubts, you can always reach us on
[Twitter][], [LinkedIn][], and [Reddit][]. Thank you for checking out this
[Twitter][], [LinkedIn][], and [Reddit][]. Thank you for checking out this
post for a different perspective on simple Ansible concepts (get it?;)).
post for a different perspective on simple Ansible concepts (get it?;)).
[LinkedIn]: https://www.linkedin.com/showcase/xlab-steampunk/
[LinkedIn]: https://www.linkedin.com/showcase/xlab-steampunk/
(XLAB Steampunk LinkedIn page)
(XLAB Steampunk LinkedIn page)
[Twitter]: https://twitter.com/xlab_si
[Twitter]: https://twitter.com/xlab_si
(XLAB's Twitter account)
(XLAB's Twitter account)
[Reddit]: https://www.reddit.com/r/ansible/comments/ha1foh/enforcing_compliance_using_the_aws_ansible/
[Reddit]: https://www.reddit.com/r/ansible/comments/ha1foh/enforcing_compliance_using_the_aws_ansible/
(Reddit page for this post)
(Reddit page for this post)
So long!
So long!