Skip to content

Commit

Permalink
Update identity support in sqlserver (ansible-collections#1626)
Browse files Browse the repository at this point in the history
* Update identity support in sqlserver

Update identity to support UserAssigned and
SystemAssigned,UserAssigned.

* Update plugins/modules/azure_rm_sqlserver.py

Co-authored-by: Fred-sun <37327967+Fred-sun@users.noreply.github.com>

---------

Co-authored-by: Fred-sun <37327967+Fred-sun@users.noreply.github.com>
  • Loading branch information
p3ck and Fred-sun authored Aug 27, 2024
1 parent c4c81f1 commit 58a7f2a
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 5 deletions.
79 changes: 74 additions & 5 deletions plugins/modules/azure_rm_sqlserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,26 @@
type: str
identity:
description:
- The identity type. Set this to C(SystemAssigned) in order to automatically create and assign an Azure Active Directory principal for the resource.
- Possible values include C(SystemAssigned).
- Specifies the managed identity to be used with SqlServer.
- If a string, the Managed identity type is based on the name.
- Possible values include C(SystemAssigned) and C(None).
- If a dict with the keys I(type), I(user_assigned_identities)
- Possible values for I(type) include C(SystemAssigned, C(UserAssigned),
C(SystemAssigned, UserAssigned), and C(None).
- Possible values for I(user_assigned_identities) include a dict
with I(id) and I(append).
- Possible values for I(id) is a list of user assigned identities ID's
- Possible values for I(append) is a boolean of True to append identities
or False to overwrite with new I(id)'s.
- The string format is (deprecated) and the new dict format should be used
going forward.
type: raw
primary_user_assigned_identity_id:
description:
- Specifies the primary User Assigned Identity to use.
- This is required if you are using Managed Identity type of UserAssigned
type: str
version_added: "2.7.0"
minimal_tls_version:
description:
- Require clients to use a specified TLS version.
Expand Down Expand Up @@ -197,6 +214,7 @@
try:
from azure.core.exceptions import ResourceNotFoundError
from azure.core.polling import LROPoller
from azure.mgmt.sql.models import (ResourceIdentity, UserIdentity)
except ImportError:
# This is handled in azure_rm_common
pass
Expand Down Expand Up @@ -243,7 +261,10 @@ def __init__(self):
type='str'
),
identity=dict(
type='str'
type='raw'
),
primary_user_assigned_identity_id=dict(
type='str',
),
minimal_tls_version=dict(
type="str",
Expand Down Expand Up @@ -277,16 +298,52 @@ def __init__(self):
self.name = None
self.parameters = dict()
self.tags = None
# Managed Identity
self.identity = None

self.results = dict(changed=False)
self.state = None
self.to_do = Actions.NoAction
self.change_admin_password = False
self._managed_identity = None

super(AzureRMSqlServer, self).__init__(derived_arg_spec=self.module_arg_spec,
supports_check_mode=True,
supports_tags=True)

@property
def managed_identity(self):
if not self._managed_identity:
self._managed_identity = {"identity": ResourceIdentity,
"user_assigned": UserIdentity
}
return self._managed_identity

def validate_identity_parameter(self):
errors = []
valid_identity_keys = ['type', 'user_assigned_identities']
valid_user_assigned_keys = ['id', 'append']
type_choices = ['SystemAssigned',
'UserAssigned',
'SystemAssigned, UserAssigned',
'None']
for key in self.identity.keys():
if key not in valid_identity_keys:
errors.append("Invalid key {0}".format(key))
# Default option for type is "None"
self.identity["type"] = self.identity.get("type", "None")
if self.identity.get("type") not in type_choices:
errors.append("Invalid identity->type, Valid choices are: [{0}]".format(type_choices))
for key in self.identity.get("user_assigned_identities", dict()).keys():
if key not in valid_user_assigned_keys:
errors.append("Invalid key {0}".format(key))
if key == "append":
if isinstance(self.identity['user_assigned_identities'][key], bool) is not True:
errors.append("identity->user_assigned_identity->append must be True or False")

if errors:
self.fail(msg="Some required options are missing from managed identity configuration.", errors=errors)

def exec_module(self, **kwargs):
"""Main module execution method"""

Expand All @@ -298,8 +355,8 @@ def exec_module(self, **kwargs):
self.parameters.update({"administrator_login": kwargs[key]})
elif key == "admin_password":
self.parameters.update({"administrator_login_password": kwargs[key]})
elif key == "identity":
self.parameters.update({"identity": {"type": kwargs[key]}})
elif key == "primary_user_assigned_identity_id":
self.parameters.update({"primary_user_assigned_identity_id": kwargs[key]})
else:
self.parameters[key] = kwargs[key]

Expand All @@ -313,6 +370,18 @@ def exec_module(self, **kwargs):

old_response = self.get_sqlserver()

if self.identity and isinstance(self.identity, dict):
self.validate_identity_parameter()
update_identity, identity = self.update_managed_identity(old_response and old_response.get('identity'),
self.identity)
if update_identity:
self.parameters.update({"identity": identity.as_dict()})
elif self.identity and isinstance(self.identity, str):
self.parameters.update({"identity": {"type": self.identity}})
self.module.warn('Specifying the identity type as a string is deprecated, please update your playbook.')
elif self.identity:
self.fail("parameter error: expecting identity to be a string or dict not {0}".format(type(self.identity).__name__))

if not old_response:
self.log("SQL Server instance doesn't exist")
if self.state == 'absent':
Expand Down
25 changes: 25 additions & 0 deletions plugins/modules/azure_rm_sqlserver_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,30 @@
- Tenant ID of the Azure AD administrator.
type: str
sample: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
identity:
description:
- Identity for the Server.
type: complex
returned: when available
contains:
type:
description:
- Type of the managed identity
returned: always
sample: UserAssigned
type: str
user_assigned_identities:
description:
- User Assigned Managed Identities and its options
returned: always
type: complex
contains:
id:
description:
- Dict of the user assigned identities IDs associated to the Resource
returned: always
type: dict
elements: dict
'''

from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMModuleBase
Expand Down Expand Up @@ -282,6 +306,7 @@ def format_results(self, response):
"sid": administrators.get("sid"),
"tenant_id": administrators.get("tenant_id"),
},
"identity": response.get("identity"),
}


Expand Down
73 changes: 73 additions & 0 deletions tests/integration/targets/azure_rm_sqlserver/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
- name: Gather Resource Group info
azure.azcollection.azure_rm_resourcegroup_info:
name: "{{ resource_group }}"
register: __rg_info

- name: Prepare random number
ansible.builtin.set_fact:
random_postfix: "{{ 1000 | random }}{{ resource_group | hash('md5') | truncate(7, True, '') }}"
tenant_id: "{{ azure_tenant }}"
run_azuread_tests: false
azuread_group_name: "Test Security Group"
azuread_group_id: "00000000-0000-0000-0000-000000000000"
location: "{{ __rg_info.resourcegroups.0.location }}"
run_once: true

- name: Create User Managed Identities
azure_rm_resource:
resource_group: "{{ resource_group }}"
provider: ManagedIdentity
resource_type: userAssignedIdentities
resource_name: "{{ item }}"
api_version: "2023-01-31"
body:
location: "{{ location }}"
state: present
loop:
- "ansible-test-sqlsvr-identity"
- "ansible-test-sqlsvr-identity-2"

- name: Set identities IDs to test. Identities ansible-test-webapp-identity and ansible-test-webapp-identity-2 have to be created previously
ansible.builtin.set_fact:
user_identity_1: "/subscriptions/{{ azure_subscription_id }}/resourcegroups/{{ resource_group }}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ansible-test-sqlsvr-identity"
user_identity_2: "/subscriptions/{{ azure_subscription_id }}/resourcegroups/{{ resource_group }}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ansible-test-sqlsvr-identity-2"

- name: Create instance of SQL Server -- check mode
azure_rm_sqlserver:
resource_group: "{{ resource_group }}"
name: "sqlsrv{{ random_postfix }}"
location: eastus
admin_username: mylogin
admin_password: Password123!
identity: SystemAssigned
check_mode: true
register: output
- name: Assert the resource instance is well created
Expand All @@ -28,6 +54,7 @@
location: eastus
admin_username: mylogin
admin_password: Password123!
identity: SystemAssigned
tags:
aaa: bbb
register: output
Expand All @@ -37,13 +64,24 @@
- output.changed
- output.state == 'Ready'

- name: Gather facts SQL Server
azure_rm_sqlserver_info:
resource_group: "{{ resource_group }}"
server_name: "sqlsrv{{ random_postfix }}"
register: output
- name: Assert that SQL Server identity.type == SystemAssigned
ansible.builtin.assert:
that:
- output.servers["sqlsrv" + random_postfix ].identity.type == "SystemAssigned"

- name: Create again instance of SQL Server
azure_rm_sqlserver:
resource_group: "{{ resource_group }}"
name: "sqlsrv{{ random_postfix }}"
location: eastus
admin_username: mylogin
admin_password: Password123!
identity: SystemAssigned
register: output
- name: Assert the state has not changed
ansible.builtin.assert:
Expand All @@ -61,6 +99,12 @@
minimal_tls_version: '1.2'
public_network_access: Disabled
restrict_outbound_network_access: Enabled
primary_user_assigned_identity_id: "{{ user_identity_1 }}"
identity:
type: UserAssigned
user_assigned_identities:
id:
- "{{ user_identity_1 }}"
tags:
aaa: bbb
register: output
Expand All @@ -70,6 +114,17 @@
- output.changed
- output.state == 'Ready'

- name: Gather facts SQL Server
azure_rm_sqlserver_info:
resource_group: "{{ resource_group }}"
server_name: "sqlsrv-extended-{{ random_postfix }}"
register: output
- name: Assert that user_identity_1 in SQL Server
ansible.builtin.assert:
that:
- output.servers["sqlsrv-extended-" + random_postfix ].identity.type == "UserAssigned"
- user_identity_1 in output.servers["sqlsrv-extended-" + random_postfix ].identity.user_assigned_identities

- name: Create extended instance of SQL Server - idempotent
azure_rm_sqlserver:
resource_group: "{{ resource_group }}"
Expand All @@ -80,6 +135,12 @@
minimal_tls_version: '1.2'
public_network_access: Disabled
restrict_outbound_network_access: Enabled
primary_user_assigned_identity_id: "{{ user_identity_1 }}"
identity:
type: UserAssigned
user_assigned_identities:
id:
- "{{ user_identity_1 }}"
tags:
aaa: bbb
register: output
Expand Down Expand Up @@ -838,3 +899,15 @@
name: "sqlsrv-azuread-{{ random_postfix }}"
state: absent
when: run_azuread_tests | bool

- name: Destroy User Managed Identities
azure_rm_resource:
resource_group: "{{ resource_group }}"
provider: ManagedIdentity
resource_type: userAssignedIdentities
resource_name: "{{ item }}"
api_version: "2023-01-31"
state: absent
loop:
- "ansible-test-sqlsvr-identity"
- "ansible-test-sqlsvr-identity-2"

0 comments on commit 58a7f2a

Please sign in to comment.