diff --git a/changelogs/fragments/963-elb_application_lb-support-alb-attributes.yml b/changelogs/fragments/963-elb_application_lb-support-alb-attributes.yml new file mode 100644 index 00000000000..bceede7877b --- /dev/null +++ b/changelogs/fragments/963-elb_application_lb-support-alb-attributes.yml @@ -0,0 +1,2 @@ +minor_changes: + - elb_application_lb - Add support for alb specific attributes and check_mode support for modifying them (https://github.com/ansible-collections/community.aws/pull/963). diff --git a/plugins/modules/elb_application_lb.py b/plugins/modules/elb_application_lb.py index 448eba4c1aa..430647e7995 100644 --- a/plugins/modules/elb_application_lb.py +++ b/plugins/modules/elb_application_lb.py @@ -49,13 +49,38 @@ deletion_protection: description: - Indicates whether deletion protection for the ALB is enabled. - - Defaults to C(false). + - Defaults to C(False). type: bool http2: description: - Indicates whether to enable HTTP2 routing. - - Defaults to C(false). + - Defaults to C(True). type: bool + http_desync_mitigation_mode: + description: + - Determines how the load balancer handles requests that might pose a security risk to an application. + - Defaults to C('defensive') + type: str + choices: ['monitor', 'defensive', 'strictest'] + version_added: 3.2.0 + http_drop_invalid_header_fields: + description: + - Indicates whether HTTP headers with invalid header fields are removed by the load balancer C(True) or routed to targets C(False). + - Defaults to C(False). + type: bool + version_added: 3.2.0 + http_x_amzn_tls_version_and_cipher_suite: + description: + - Indicates whether the two headers are added to the client request before sending it to the target. + - Defaults to C(False). + type: bool + version_added: 3.2.0 + http_xff_client_port: + description: + - Indicates whether the X-Forwarded-For header should preserve the source port that the client used to connect to the load balancer. + - Defaults to C(False). + type: bool + version_added: 3.2.0 idle_timeout: description: - The number of seconds to wait before an idle connection is closed. @@ -183,6 +208,12 @@ - Sets the type of IP addresses used by the subnets of the specified Application Load Balancer. choices: [ 'ipv4', 'dualstack' ] type: str + waf_fail_open: + description: + - Indicates whether to allow a AWS WAF-enabled load balancer to route requests to targets if it is unable to forward the request to AWS WAF. + - Defaults to C(False). + type: bool + version_added: 3.2.0 extends_documentation_fragment: - amazon.aws.aws - amazon.aws.ec2 @@ -554,6 +585,13 @@ def create_or_update_alb(alb_obj): alb_obj.module.exit_json(changed=True, msg='Would have updated ALB if not in check mode.') alb_obj.modify_security_groups() + # ALB attributes + if not alb_obj.compare_elb_attributes(): + if alb_obj.module.check_mode: + alb_obj.module.exit_json(changed=True, msg='Would have updated ALB if not in check mode.') + alb_obj.update_elb_attributes() + alb_obj.modify_elb_attributes() + # Tags - only need to play with tags if tags parameter has been set to something if alb_obj.tags is not None: @@ -578,10 +616,6 @@ def create_or_update_alb(alb_obj): alb_obj.module.exit_json(changed=True, msg='Would have created ALB if not in check mode.') alb_obj.create_elb() - # ALB attributes - alb_obj.update_elb_attributes() - alb_obj.modify_elb_attributes() - # Listeners listeners_obj = ELBListeners(alb_obj.connection, alb_obj.module, alb_obj.elb['LoadBalancerArn']) listeners_to_add, listeners_to_modify, listeners_to_delete = listeners_obj.compare_listeners() @@ -712,6 +746,10 @@ def main(): access_logs_s3_prefix=dict(type='str'), deletion_protection=dict(type='bool'), http2=dict(type='bool'), + http_desync_mitigation_mode=dict(type='str', choices=['monitor', 'defensive', 'strictest']), + http_drop_invalid_header_fields=dict(type='bool'), + http_x_amzn_tls_version_and_cipher_suite=dict(type='bool'), + http_xff_client_port=dict(type='bool'), idle_timeout=dict(type='int'), listeners=dict(type='list', elements='dict', @@ -732,6 +770,7 @@ def main(): scheme=dict(default='internet-facing', choices=['internet-facing', 'internal']), state=dict(choices=['present', 'absent'], default='present'), tags=dict(type='dict'), + waf_fail_open=dict(type='bool'), wait_timeout=dict(type='int'), wait=dict(default=False, type='bool'), purge_rules=dict(default=True, type='bool'), diff --git a/tests/integration/targets/elb_application_lb/tasks/main.yml b/tests/integration/targets/elb_application_lb/tasks/main.yml index 81ebf4cdfce..f4a2f2658be 100644 --- a/tests/integration/targets/elb_application_lb/tasks/main.yml +++ b/tests/integration/targets/elb_application_lb/tasks/main.yml @@ -330,6 +330,12 @@ - alb is changed - alb.ip_address_type == 'dualstack' - alb.listeners[0].rules | length == 1 + - alb.routing_http2_enabled | bool + - alb.routing_http_desync_mitigation_mode == 'defensive' + - not alb.routing_http_drop_invalid_header_fields_enabled | bool + - not alb.routing_http_x_amzn_tls_version_and_cipher_suite_enabled | bool + - not alb.routing_http_xff_client_port_enabled | bool + - not alb.waf_fail_open_enabled | bool - name: Create an ALB with ip address type (idempotence) - check_mode elb_application_lb: @@ -371,6 +377,132 @@ that: - alb is not changed - alb.ip_address_type == 'dualstack' + - alb.routing_http2_enabled | bool + - alb.routing_http_desync_mitigation_mode == 'defensive' + - not alb.routing_http_drop_invalid_header_fields_enabled | bool + - not alb.routing_http_x_amzn_tls_version_and_cipher_suite_enabled | bool + - not alb.routing_http_xff_client_port_enabled | bool + - not alb.waf_fail_open_enabled | bool + + # ------------------------------------------------------------------------------------------ + + - name: Update an ALB with different attributes - check_mode + elb_application_lb: + name: "{{ alb_name }}" + subnets: "{{ public_subnets }}" + security_groups: "{{ sec_group.group_id }}" + state: present + listeners: + - Protocol: HTTP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: 'dualstack' + http2: no + http_desync_mitigation_mode: monitor + http_drop_invalid_header_fields: yes + http_x_amzn_tls_version_and_cipher_suite: yes + http_xff_client_port: yes + waf_fail_open: yes + register: alb + check_mode: yes + + - assert: + that: + - alb is changed + - alb.msg is match('Would have updated ALB if not in check mode.') + + - name: Update an ALB with different attributes + elb_application_lb: + name: "{{ alb_name }}" + subnets: "{{ public_subnets }}" + security_groups: "{{ sec_group.group_id }}" + state: present + listeners: + - Protocol: HTTP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: 'dualstack' + http2: no + http_desync_mitigation_mode: monitor + http_drop_invalid_header_fields: yes + http_x_amzn_tls_version_and_cipher_suite: yes + http_xff_client_port: yes + waf_fail_open: yes + register: alb + + - assert: + that: + - alb is changed + - alb.ip_address_type == 'dualstack' + - not alb.routing_http2_enabled | bool + - alb.routing_http_desync_mitigation_mode == 'monitor' + - alb.routing_http_drop_invalid_header_fields_enabled | bool + - alb.routing_http_x_amzn_tls_version_and_cipher_suite_enabled | bool + - alb.routing_http_xff_client_port_enabled | bool + - alb.waf_fail_open_enabled | bool + + - name: Update an ALB with different attributes (idempotence) - check_mode + elb_application_lb: + name: "{{ alb_name }}" + subnets: "{{ public_subnets }}" + security_groups: "{{ sec_group.group_id }}" + state: present + listeners: + - Protocol: HTTP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: 'dualstack' + http2: no + http_desync_mitigation_mode: monitor + http_drop_invalid_header_fields: yes + http_x_amzn_tls_version_and_cipher_suite: yes + http_xff_client_port: yes + waf_fail_open: yes + register: alb + check_mode: yes + + - assert: + that: + - alb is not changed + - alb.msg is match('IN CHECK MODE - no changes to make to ALB specified.') + + - name: Update an ALB with different attributes (idempotence) + elb_application_lb: + name: "{{ alb_name }}" + subnets: "{{ public_subnets }}" + security_groups: "{{ sec_group.group_id }}" + state: present + listeners: + - Protocol: HTTP + Port: 80 + DefaultActions: + - Type: forward + TargetGroupName: "{{ tg_name }}" + ip_address_type: 'dualstack' + http2: no + http_desync_mitigation_mode: monitor + http_drop_invalid_header_fields: yes + http_x_amzn_tls_version_and_cipher_suite: yes + http_xff_client_port: yes + waf_fail_open: yes + register: alb + + - assert: + that: + - alb is not changed + - alb.ip_address_type == 'dualstack' + - not alb.routing_http2_enabled | bool + - alb.routing_http_desync_mitigation_mode == 'monitor' + - alb.routing_http_drop_invalid_header_fields_enabled | bool + - alb.routing_http_x_amzn_tls_version_and_cipher_suite_enabled | bool + - alb.routing_http_xff_client_port_enabled | bool + - alb.waf_fail_open_enabled | bool # ------------------------------------------------------------------------------------------ @@ -387,6 +519,12 @@ - Type: forward TargetGroupName: "{{ tg_name }}" ip_address_type: 'ipv4' + http2: no + http_desync_mitigation_mode: monitor + http_drop_invalid_header_fields: yes + http_x_amzn_tls_version_and_cipher_suite: yes + http_xff_client_port: yes + waf_fail_open: yes register: alb check_mode: yes @@ -408,12 +546,24 @@ - Type: forward TargetGroupName: "{{ tg_name }}" ip_address_type: 'ipv4' + http2: no + http_desync_mitigation_mode: monitor + http_drop_invalid_header_fields: yes + http_x_amzn_tls_version_and_cipher_suite: yes + http_xff_client_port: yes + waf_fail_open: yes register: alb - assert: that: - alb is changed - alb.ip_address_type == 'ipv4' + - not alb.routing_http2_enabled | bool + - alb.routing_http_desync_mitigation_mode == 'monitor' + - alb.routing_http_drop_invalid_header_fields_enabled | bool + - alb.routing_http_x_amzn_tls_version_and_cipher_suite_enabled | bool + - alb.routing_http_xff_client_port_enabled | bool + - alb.waf_fail_open_enabled | bool - name: Update an ALB with different ip address type (idempotence) - check_mode elb_application_lb: @@ -428,6 +578,12 @@ - Type: forward TargetGroupName: "{{ tg_name }}" ip_address_type: 'ipv4' + http2: no + http_desync_mitigation_mode: monitor + http_drop_invalid_header_fields: yes + http_x_amzn_tls_version_and_cipher_suite: yes + http_xff_client_port: yes + waf_fail_open: yes register: alb check_mode: yes @@ -449,12 +605,24 @@ - Type: forward TargetGroupName: "{{ tg_name }}" ip_address_type: 'ipv4' + http2: no + http_desync_mitigation_mode: monitor + http_drop_invalid_header_fields: yes + http_x_amzn_tls_version_and_cipher_suite: yes + http_xff_client_port: yes + waf_fail_open: yes register: alb - assert: that: - alb is not changed - alb.ip_address_type == 'ipv4' + - not alb.routing_http2_enabled | bool + - alb.routing_http_desync_mitigation_mode == 'monitor' + - alb.routing_http_drop_invalid_header_fields_enabled | bool + - alb.routing_http_x_amzn_tls_version_and_cipher_suite_enabled | bool + - alb.routing_http_xff_client_port_enabled | bool + - alb.waf_fail_open_enabled | bool # ------------------------------------------------------------------------------------------