Repository: ansible/ansible

Issue:
ec2_group rules_egress
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report
 - Documentation Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
ec2_group task
rules_egress option parameter

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.2.0.0
  config file = /home/jayen/.ansible.cfg
  configured module search path = Default w/o overrides
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
```
[ssh_connection]
control_path = /tmp/control_%%l_%%h_%%p_%%r
```

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->
debian jessie managing EC2

##### SUMMARY
<!--- Explain the problem briefly -->
Docs say: `If none are supplied, a default all-out rule is assumed.` but I didn't supply `rules_egress` as an option parameter and ansible did not create the default all-out rule.  More info here: https://forums.aws.amazon.com/thread.jspa?threadID=246610

Seems to be the opposite of https://github.com/ansible/ansible/issues/19226

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: ec2_group default
  ec2_group:
    name: default
    description: for all EC2 systems to contact each other
    region: "{{ aws_region }}"
    aws_access_key: "{{ ec2_access_key }}"
    aws_secret_key: "{{ ec2_secret_key }}"
    rules:
      - proto: all
        # the containing group name may be specified here
        group_name: default
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
a default all-out rule is created

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
a default all-out rule was not created

<!--- Paste verbatim command output between quotes below -->
```
AWS_ACCESS_KEY_ID={{ ec2_access_key }} AWS_SECRET_ACCESS_KEY={{ ec2_secret_key }} ansible-playbook --inventory inventory ec2.yaml --vault-password-file=.password
```

ec2_group rules_egress
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report
 - Documentation Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
ec2_group task
rules_egress option parameter

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.2.0.0
  config file = /home/jayen/.ansible.cfg
  configured module search path = Default w/o overrides
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
```
[ssh_connection]
control_path = /tmp/control_%%l_%%h_%%p_%%r
```

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->
debian jessie managing EC2

##### SUMMARY
<!--- Explain the problem briefly -->
Docs say: `If none are supplied, a default all-out rule is assumed.` but I didn't supply `rules_egress` as an option parameter and ansible did not create the default all-out rule.  More info here: https://forums.aws.amazon.com/thread.jspa?threadID=246610

Seems to be the opposite of https://github.com/ansible/ansible/issues/19226

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: ec2_group default
  ec2_group:
    name: default
    description: for all EC2 systems to contact each other
    region: "{{ aws_region }}"
    aws_access_key: "{{ ec2_access_key }}"
    aws_secret_key: "{{ ec2_secret_key }}"
    rules:
      - proto: all
        # the containing group name may be specified here
        group_name: default
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
a default all-out rule is created

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
a default all-out rule was not created

<!--- Paste verbatim command output between quotes below -->
```
AWS_ACCESS_KEY_ID={{ ec2_access_key }} AWS_SECRET_ACCESS_KEY={{ ec2_secret_key }} ansible-playbook --inventory inventory ec2.yaml --vault-password-file=.password
```



Discussion:
I just wasted hours trying to debug this because you don't really ever think about security group egress being blank, do you? There isn't even a quick table to check in the EC2 Description like there is for aggregating ingress rules, probably because they're so infrequently modified. 

Well the docs completely contradict the actual current behavior, and if you simply define ingress rules (i.e. `rules:`), it removes the default allow egress rule! If it's the only security group, OR it's combined with another security group which has also had its egress rule of `0.0.0.0/0` removed, normal egress connections that aren't stateful _stop working_! This can lead to a lot of confusion if your workflow is to have multiple groups per instance, as some may have the default allow egress rule, and some may not, leading you to scratch your head over why normal internet connectivity is broken for some and not others.

>\- rules_egress
        List of firewall outbound rules to enforce in this group (see example). **If none are supplied, a
        default all-out rule is assumed.** If an empty list is supplied, no outbound rules will be enabled.
        [Default: (null)]

(emphasis mine) 
Additionally, the "workaround" for this is to set `purge_rules_egress: false` but I'd like to point out that this is nonsensical still due to the fact that the user must know that there is a default egress rule of `ALL ALL 0.0.0.0/0` by default *that they would be purging  otherwise*. The other option is to statically define the Allow all egress rule for each group.

I much prefer the documented behavior than what it is actually doing.

This was once fixed before by @jimi-c here: https://github.com/ansible/ansible/commit/0dabb37337556a664b4c982561231483e5269c8e, though I'm not really sure when it deviated from that behavior
Related tickets:
 - #19226
 - #11249 
I just wasted hours trying to debug this because you don't really ever think about security group egress being blank, do you? There isn't even a quick table to check in the EC2 Description like there is for aggregating ingress rules, probably because they're so infrequently modified. 

Well the docs completely contradict the actual current behavior, and if you simply define ingress rules (i.e. `rules:`), it removes the default allow egress rule! If it's the only security group, OR it's combined with another security group which has also had its egress rule of `0.0.0.0/0` removed, normal egress connections that aren't stateful _stop working_! This can lead to a lot of confusion if your workflow is to have multiple groups per instance, as some may have the default allow egress rule, and some may not, leading you to scratch your head over why normal internet connectivity is broken for some and not others.

>\- rules_egress
        List of firewall outbound rules to enforce in this group (see example). **If none are supplied, a
        default all-out rule is assumed.** If an empty list is supplied, no outbound rules will be enabled.
        [Default: (null)]

(emphasis mine) 
Additionally, the "workaround" for this is to set `purge_rules_egress: false` but I'd like to point out that this is nonsensical still due to the fact that the user must know that there is a default egress rule of `ALL ALL 0.0.0.0/0` by default *that they would be purging  otherwise*. The other option is to statically define the Allow all egress rule for each group.

I much prefer the documented behavior than what it is actually doing.

This was once fixed before by @jimi-c here: https://github.com/ansible/ansible/commit/0dabb37337556a664b4c982561231483e5269c8e, though I'm not really sure when it deviated from that behavior
Related tickets:
 - #19226
 - #11249 

Resolving patch:
diff --git a/lib/ansible/modules/cloud/amazon/ec2_group.py b/lib/ansible/modules/cloud/amazon/ec2_group.py
--- a/lib/ansible/modules/cloud/amazon/ec2_group.py
+++ b/lib/ansible/modules/cloud/amazon/ec2_group.py
@@ -438,8 +438,8 @@ def main():
                                 src_group_id=grantGroup,
                                 cidr_ip=thisip)
                         changed = True
-        elif vpc_id:
-            # when using a vpc, but no egress rules are specified,
+        else:
+            # when no egress rules are specified,
             # we add in a default allow all out rule, which was the
             # default behavior before egress rules were added
             default_egress_rule = 'out--1-None-None-None-0.0.0.0/0'


Test patch: