Repository: ansible-collections/amazon.aws

Issue:
rds_instance module ignores 'ca_certificate_identifier' Parameter value
### Summary

When I try to create or modify an existing RDS instance ca certificate value the rds_instance module ignores the value set for ca_certificate_idenifier and lets AWS use the default value instead.

### Issue Type

Bug Report

### Component Name

rds_instance

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.14.4]
  config file = ~/projects/provisioning/ansible.cfg
  configured module search path = ['~/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = ~/venv/lib/python3.9/site-packages/ansible
  ansible collection location = ~/.ansible/collections:/usr/share/ansible/collections
  executable location = ~/venv/bin/ansible
  python version = 3.9.14 (main, Oct 16 2022, 22:44:18) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] (~/venv/bin/python3.9)
  jinja version = 3.1.2
  libyaml = True
```


### Collection Versions

```console (paste below)
$ $ ansible-galaxy collection list

# ~/.ansible/collections/ansible_collections
Collection        Version
----------------- -------
amazon.aws        5.4.0  
ansible.windows   1.13.0 
community.general 6.5.0  

# ~/venv/lib/python3.9/site-packages/ansible_collections
Collection                    Version
----------------------------- -------
amazon.aws                    5.4.0  
ansible.netcommon             4.1.0  
ansible.posix                 1.5.1  
ansible.utils                 2.9.0  
ansible.windows               1.13.0 
arista.eos                    6.0.0  
awx.awx                       21.14.0
azure.azcollection            1.15.0 
check_point.mgmt              4.0.0  
chocolatey.chocolatey         1.4.0  
cisco.aci                     2.4.0  
cisco.asa                     4.0.0  
cisco.dnac                    6.6.4  
cisco.intersight              1.0.24 
cisco.ios                     4.4.0  
cisco.iosxr                   4.1.0  
cisco.ise                     2.5.12 
cisco.meraki                  2.15.1 
cisco.mso                     2.2.1  
cisco.nso                     1.0.3  
cisco.nxos                    4.1.0  
cisco.ucs                     1.8.0  
cloud.common                  2.1.3  
cloudscale_ch.cloud           2.2.4  
community.aws                 5.4.0  
community.azure               2.0.0  
community.ciscosmb            1.0.5  
community.crypto              2.11.1 
community.digitalocean        1.23.0 
community.dns                 2.5.2  
community.docker              3.4.3  
community.fortios             1.0.0  
community.general             6.5.0  
community.google              1.0.0  
community.grafana             1.5.4  
community.hashi_vault         4.2.0  
community.hrobot              1.8.0  
community.libvirt             1.2.0  
community.mongodb             1.5.1  
community.mysql               3.6.0  
community.network             5.0.0  
community.okd                 2.3.0  
community.postgresql          2.3.2  
community.proxysql            1.5.1  
community.rabbitmq            1.2.3  
community.routeros            2.8.0  
community.sap                 1.0.0  
community.sap_libs            1.4.1  
community.skydive             1.0.0  
community.sops                1.6.1  
community.vmware              3.5.0  
community.windows             1.12.0 
community.zabbix              1.9.2  
containers.podman             1.10.1 
cyberark.conjur               1.2.0  
cyberark.pas                  1.0.17 
dellemc.enterprise_sonic      2.0.0  
dellemc.openmanage            6.3.0  
dellemc.os10                  1.1.1  
dellemc.os6                   1.0.7  
dellemc.os9                   1.0.4  
dellemc.powerflex             1.5.0  
dellemc.unity                 1.5.0  
f5networks.f5_modules         1.23.0 
fortinet.fortimanager         2.1.7  
fortinet.fortios              2.2.3  
frr.frr                       2.0.0  
gluster.gluster               1.0.2  
google.cloud                  1.1.3  
grafana.grafana               1.1.1  
hetzner.hcloud                1.10.0 
hpe.nimble                    1.1.4  
ibm.qradar                    2.1.0  
ibm.spectrum_virtualize       1.11.0 
infinidat.infinibox           1.3.12 
infoblox.nios_modules         1.4.1  
inspur.ispim                  1.3.0  
inspur.sm                     2.3.0  
junipernetworks.junos         4.1.0  
kubernetes.core               2.4.0  
lowlydba.sqlserver            1.3.1  
mellanox.onyx                 1.0.0  
netapp.aws                    21.7.0 
netapp.azure                  21.10.0
netapp.cloudmanager           21.22.0
netapp.elementsw              21.7.0 
netapp.ontap                  22.4.1 
netapp.storagegrid            21.11.1
netapp.um_info                21.8.0 
netapp_eseries.santricity     1.4.0  
netbox.netbox                 3.11.0 
ngine_io.cloudstack           2.3.0  
ngine_io.exoscale             1.0.0  
ngine_io.vultr                1.1.3  
openstack.cloud               1.10.0 
openvswitch.openvswitch       2.1.0  
ovirt.ovirt                   2.4.1  
purestorage.flasharray        1.17.2 
purestorage.flashblade        1.10.0 
purestorage.fusion            1.4.1  
sensu.sensu_go                1.13.2 
splunk.es                     2.1.0  
t_systems_mms.icinga_director 1.32.2 
theforeman.foreman            3.9.0  
vmware.vmware_rest            2.3.1  
vultr.cloud                   1.7.0  
vyos.vyos                     4.0.1  
wti.remote                    1.0.4 
```


### AWS SDK versions

```console (paste below)
$ pip show boto boto3 botocore
Name: boto
Version: 2.49.0
Summary: Amazon Web Services Library
Home-page: https://github.com/boto/boto/
Author: Mitch Garnaat
Author-email: mitch@garnaat.com
License: MIT
Location: ~/venv/lib/python3.9/site-packages
Requires: 
Required-by: 
---
Name: boto3
Version: 1.26.102
Summary: The AWS SDK for Python
Home-page: https://github.com/boto/boto3
Author: Amazon Web Services
Author-email: 
License: Apache License 2.0
Location: ~/venv/lib/python3.9/site-packages
Requires: botocore, jmespath, s3transfer
Required-by: 
---
Name: botocore
Version: 1.29.102
Summary: Low-level, data-driven core of boto 3.
Home-page: https://github.com/boto/botocore
Author: Amazon Web Services
Author-email: 
License: Apache License 2.0
Location: ~/venv/lib/python3.9/site-packages
Requires: jmespath, python-dateutil, urllib3
Required-by: awscli, boto3, s3transfer
```


### Configuration

```console (paste below)
$ ansible-config dump --only-changed
ANSIBLE_PIPELINING(~/projects/provisioning/ansible.cfg) = True
CONFIG_FILE() = ~/projects/provisioning/ansible.cfg
DEFAULT_FORKS(~/projects/provisioning/ansible.cfg) = 1000
DEFAULT_HOST_LIST(~/projects/provisioning/ansible.cfg) = ['~/projects/provisioning/ansible_plugins']
DEFAULT_LOAD_CALLBACK_PLUGINS(~/projects/provisioning/ansible.cfg) = True
DEFAULT_LOG_PATH(~/projects/provisioning/ansible.cfg) = ~/projects/provisioning/log/ansible
DEFAULT_ROLES_PATH(~/projects/provisioning/ansible.cfg) = ['~/projects/provisioning/roles']
DEFAULT_STDOUT_CALLBACK(~/projects/provisioning/ansible.cfg) = yaml
HOST_KEY_CHECKING(~/projects/provisioning/ansible.cfg) = False
```


### OS / Environment

Centos 7

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
- name: Modify RDS Database
  amazon.aws.rds_instance:
    apply_immediately: true
    region: ap-southeast-2b
    db_instance_identifier: my-rds-db
    state: present
    engine_version: postgres
    iops: 3000
    ca_certificate_identifier: rds-ca-ecc384-g1
    allocated_storage: 2000
    copy_tags_to_snapshot: true
    backup_retention_period: 0
    preferred_backup_window: "13:00-13:30"
    preferred_maintenance_window: "mon:14:00-mon:14:30"
    allow_major_version_upgrade: true
    auto_minor_version_upgrade: true
    wait: yes
```


### Expected Results

```
  ca_certificate_identifier: rds-ca-ecc384-g1
  certificate_details:
    ca_identifier: rds-ca-ecc384-g1
    valid_till: '2024-04-06T05:43:19+00:00'
``` 
The CA root certificate for SSL connections should be 'rds-ca-ecc384-g1'.

### Actual Results

```console (paste below)
  ca_certificate_identifier: rds-ca-2019
  certificate_details:
    ca_identifier: rds-ca-2019
    valid_till: '2024-08-22T17:08:50+00:00'
```
The CA root certificate for SSL connections is the current AWS default 'rds-ca-2019', not the new one.

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:

Resolving patch:
diff --git a/plugins/module_utils/rds.py b/plugins/module_utils/rds.py
--- a/plugins/module_utils/rds.py
+++ b/plugins/module_utils/rds.py
@@ -363,7 +363,7 @@ def arg_spec_to_rds_params(options_dict):
         processor_features = options_dict.pop("processor_features")
     camel_options = snake_dict_to_camel_dict(options_dict, capitalize_first=True)
     for key in list(camel_options.keys()):
-        for old, new in (("Db", "DB"), ("Iam", "IAM"), ("Az", "AZ")):
+        for old, new in (("Db", "DB"), ("Iam", "IAM"), ("Az", "AZ"), ("Ca", "CA")):
             if old in key:
                 camel_options[key.replace(old, new)] = camel_options.pop(key)
     camel_options["Tags"] = tags
diff --git a/plugins/modules/rds_instance.py b/plugins/modules/rds_instance.py
--- a/plugins/modules/rds_instance.py
+++ b/plugins/modules/rds_instance.py
@@ -580,7 +580,9 @@
   type: int
   sample: 1
 ca_certificate_identifier:
-  description: The identifier of the CA certificate for the DB instance.
+  description:
+    - The identifier of the CA certificate for the DB instance.
+    - Requires minimum botocore version 1.29.44.
   returned: always
   type: str
   sample: rds-ca-2015
@@ -1019,7 +1021,10 @@ def get_options_with_changing_values(client, module, parameters):
     apply_immediately = parameters.pop("ApplyImmediately", None)
     cloudwatch_logs_enabled = module.params["enable_cloudwatch_logs_exports"]
     purge_security_groups = module.params["purge_security_groups"]
+    ca_certificate_identifier = module.params["ca_certificate_identifier"]
 
+    if ca_certificate_identifier:
+        parameters["CACertificateIdentifier"] = ca_certificate_identifier
     if port:
         parameters["DBPortNumber"] = port
     if not force_update_password:
@@ -1394,7 +1399,7 @@ def main():
         auto_minor_version_upgrade=dict(type="bool"),
         availability_zone=dict(aliases=["az", "zone"]),
         backup_retention_period=dict(type="int"),
-        ca_certificate_identifier=dict(),
+        ca_certificate_identifier=dict(type="str"),
         character_set_name=dict(),
         copy_tags_to_snapshot=dict(type="bool"),
         db_cluster_identifier=dict(aliases=["cluster_id"]),
@@ -1487,6 +1492,11 @@ def main():
         supports_check_mode=True,
     )
 
+    if module.params["ca_certificate_identifier"]:
+        module.require_botocore_at_least(
+            "1.29.44", reason="to use 'ca_certificate_identifier' while creating/updating rds instance"
+        )
+
     # Sanitize instance identifiers
     module.params["db_instance_identifier"] = module.params["db_instance_identifier"].lower()
     if module.params["new_db_instance_identifier"]:


Test patch:
diff --git a/tests/integration/targets/rds_instance_modify/meta/main.yml b/tests/integration/targets/rds_instance_modify/meta/main.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/rds_instance_modify/meta/main.yml
@@ -0,0 +1,5 @@
+---
+dependencies:
+   - role: setup_botocore_pip
+     vars:
+        botocore_version: "1.29.44"
\ No newline at end of file
diff --git a/tests/integration/targets/rds_instance_modify/tasks/main.yml b/tests/integration/targets/rds_instance_modify/tasks/main.yml
--- a/tests/integration/targets/rds_instance_modify/tasks/main.yml
+++ b/tests/integration/targets/rds_instance_modify/tasks/main.yml
@@ -193,6 +193,119 @@
       - result.changed
       - result.db_instance_identifier == "{{ modified_instance_id }}"
 
+
+  # Test modifying CA certificate identifier -------------------------------------------
+
+  - name: Modify the CA certificate identifier to rds-ca-ecc384-g1 - check_mode
+    rds_instance:
+      state: present
+      db_instance_identifier: '{{ modified_instance_id }}'
+      allow_major_version_upgrade: true
+      ca_certificate_identifier: rds-ca-ecc384-g1
+      apply_immediately: true
+      tags:
+        Name: '{{ modified_instance_id }}'
+        Created_by: Ansible rds_instance tests
+    register: result
+    check_mode: true
+    vars:
+      ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
+
+  - name: Get curent CA certificate identifier
+    rds_instance_info:
+      db_instance_identifier: '{{ modified_instance_id }}'
+    register: db_info
+  - name: Assert that CA certificate identifier has been modified - check_mode
+    assert:
+      that:
+        - result is changed
+        - result is not failed
+        - db_info.instances[0].ca_certificate_identifier != "rds-ca-ecc384-g1"
+
+  - name: Modify the CA certificate identifier to rds-ca-ecc384-g1
+    rds_instance:
+      state: present
+      db_instance_identifier: '{{ modified_instance_id }}'
+      allow_major_version_upgrade: true
+      ca_certificate_identifier: rds-ca-ecc384-g1
+      apply_immediately: true
+      tags:
+        Name: '{{ modified_instance_id }}'
+        Created_by: Ansible rds_instance tests
+    register: result
+    vars:
+      ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
+
+  - name: Get curent CA certificate identifier
+    rds_instance_info:
+      db_instance_identifier: '{{ modified_instance_id }}'
+    register: db_info
+    retries: 20
+    delay: 10
+    until: db_info.instances[0].ca_certificate_identifier == "rds-ca-ecc384-g1"
+  - name: Assert that CA certificate identifier has been modified
+    assert:
+      that:
+        - result is changed
+        - result is not failed
+        - db_info.instances[0].ca_certificate_identifier == "rds-ca-ecc384-g1"
+
+  - name: Modify the CA certificate identifier to rds-ca-ecc384-g1 - idempotent
+    rds_instance:
+      state: present
+      db_instance_identifier: '{{ modified_instance_id }}'
+      ca_certificate_identifier: rds-ca-ecc384-g1
+      apply_immediately: true
+      tags:
+        Name: '{{ modified_instance_id }}'
+        Created_by: Ansible rds_instance tests
+    register: result
+    vars:
+      ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
+
+  - name: Get curent CA certificate identifier
+    rds_instance_info:
+      db_instance_identifier: '{{ modified_instance_id }}'
+    register: db_info
+    retries: 20
+    delay: 10
+    until: db_info.instances[0].ca_certificate_identifier == "rds-ca-ecc384-g1"
+  - name: Assert that CA certificate identifier has been modified
+    assert:
+      that:
+        - result is not changed
+        - result is not failed
+        - db_info.instances[0].ca_certificate_identifier == "rds-ca-ecc384-g1"
+
+  - name: Modify the CA certificate identifier to rds-ca-ecc384-g1 - idempotent - check_mode
+    rds_instance:
+      state: present
+      db_instance_identifier: '{{ modified_instance_id }}'
+      ca_certificate_identifier: rds-ca-ecc384-g1
+      apply_immediately: true
+      tags:
+        Name: '{{ modified_instance_id }}'
+        Created_by: Ansible rds_instance tests
+    register: result
+    check_mode: true
+    vars:
+      ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}"
+
+  - name: Get curent CA certificate identifier
+    rds_instance_info:
+      db_instance_identifier: '{{ modified_instance_id }}'
+    register: db_info
+    retries: 20
+    delay: 10
+    until: db_info.instances[0].ca_certificate_identifier == "rds-ca-ecc384-g1"
+  - name: Assert that CA certificate identifier has been modified
+    assert:
+      that:
+        - result is not changed
+        - result is not failed
+        - db_info.instances[0].ca_certificate_identifier == "rds-ca-ecc384-g1"
+  # Test modifying CA certificate identifier Complete-------------------------------------------
+
   always:
   - name: Delete the instance
     rds_instance: