Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a2f6b6c
Initial updates to use track 2 Hub GA SDK
c-ryan-k Mar 3, 2021
45cadfb
WIP initial user-assigned identity functionality
c-ryan-k Mar 16, 2021
2acf8e6
Added routing endpoint identity and added some preliminary test code
c-ryan-k Mar 17, 2021
b613397
Updated identity code with enums and minor logic updates
c-ryan-k Mar 18, 2021
b3208a4
More identity updates, role and scope assignment
c-ryan-k Mar 18, 2021
ee48812
Minor fixes to identity functions and return values
c-ryan-k Mar 19, 2021
ee807a0
Linting fixes
c-ryan-k Mar 19, 2021
ea84c66
WIP testing updates
c-ryan-k Mar 19, 2021
44117af
Merge branch 'azure-dev' into hub_track2
c-ryan-k Mar 26, 2021
fa2dbb8
Help/Param updates and minor tweaks/fixes
c-ryan-k Mar 30, 2021
691950d
Test updates, help updates, polling updates
c-ryan-k Mar 30, 2021
8fc4f2e
Test recording updates
c-ryan-k Mar 31, 2021
1282c05
test updates
c-ryan-k Apr 6, 2021
0a76443
minor fix in consumer_group_create, test updates
c-ryan-k Apr 6, 2021
5060def
Initial updates to use track 2 Hub GA SDK
c-ryan-k Mar 3, 2021
14fa27d
WIP initial user-assigned identity functionality
c-ryan-k Mar 16, 2021
bc5e641
Added routing endpoint identity and added some preliminary test code
c-ryan-k Mar 17, 2021
8779d9a
Updated identity code with enums and minor logic updates
c-ryan-k Mar 18, 2021
889f42c
More identity updates, role and scope assignment
c-ryan-k Mar 18, 2021
90342f9
Minor fixes to identity functions and return values
c-ryan-k Mar 19, 2021
9b25700
Linting fixes
c-ryan-k Mar 19, 2021
850ab5e
WIP testing updates
c-ryan-k Mar 19, 2021
a65084e
Help/Param updates and minor tweaks/fixes
c-ryan-k Mar 30, 2021
c92c45f
Test updates, help updates, polling updates
c-ryan-k Mar 30, 2021
5f5e1e2
Test recording updates
c-ryan-k Mar 31, 2021
df59fbf
test updates
c-ryan-k Apr 6, 2021
e6308da
minor fix in consumer_group_create, test updates
c-ryan-k Apr 6, 2021
47e700a
Merge branch 'hub_track2' of https://github.com/c-ryan-k/azure-cli in…
c-ryan-k Apr 12, 2021
0214f61
Test updates and new recordings
c-ryan-k Apr 12, 2021
3ea6fc4
Merge branch 'azure-dev' into hub_track2
c-ryan-k Apr 20, 2021
a29fe37
Fix for ARM issue - user identity object must be empty upon removal o…
c-ryan-k Apr 27, 2021
1a0ceeb
Updates to use stable multiapi SDK (2021-03-03) with backfill for dev…
c-ryan-k Apr 28, 2021
d1b5f0d
Merge branch 'dev' into hub_track2
c-ryan-k Apr 28, 2021
ef103b3
Help/Param string updates
c-ryan-k Apr 28, 2021
fb759e6
Version fix for new SDK (2021-03-31)
c-ryan-k Apr 29, 2021
bdc3f5a
Parameter updates
c-ryan-k May 11, 2021
a599f8b
Test and recording updates
c-ryan-k May 11, 2021
cd59e5a
Certificate create/update fixes and test updates
c-ryan-k May 11, 2021
4e8d6a3
Add DeviceConnectionStateEvents as a routing source type
c-ryan-k May 13, 2021
0ab2ae5
RoutingSource test updates
c-ryan-k May 14, 2021
20992a8
SDK version update to 2.0.0
c-ryan-k May 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
WIP initial user-assigned identity functionality
  • Loading branch information
c-ryan-k committed Mar 16, 2021
commit 45cadfb56cf353fc0489790247ef259083faa487
13 changes: 12 additions & 1 deletion src/azure-cli/azure/cli/command_modules/iot/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def load_arguments(self, _): # pylint: disable=too-many-statements
help='The connection string for the Azure Storage account to which files are uploaded.')
c.argument('fileupload_storage_authentication_type',
options_list=['--fileupload-storage-auth-type', '--fsa'],
help='The authentication type for the Azure Storage account to which files are uploaded.'
help='The authentication type for the Azure Storage account to which files are uploaded. '
'Possible values are keyBased and identityBased')
c.argument('fileupload_storage_container_uri',
options_list=['--fileupload-storage-container-uri', '--fcu'],
Expand All @@ -178,10 +178,21 @@ def load_arguments(self, _): # pylint: disable=too-many-statements
type=int, validator=validate_fileupload_sas_ttl,
help='The amount of time a SAS URI generated by IoT Hub is valid before it expires,'
' between 1 and 24 hours.')
c.argument('fileupload_storage_identity',
options_list=['--fileupload-storage-identity', '--fsi'],
help='The managed identity to use for file upload authentication.')
c.argument('min_tls_version', options_list=['--min-tls-version', '--mintls'],
type=str, help='Specify the minimum TLS version to support for this hub. Can be set to'
' "1.2" to have clients that use a TLS version below 1.2 to be rejected.')
c.argument('tags', tags_type)
c.argument('identities', options_list=['--assign-identity'],
nargs='*', help="Accepts system or user assigned identities separated by spaces. Use '[system]'"
" to refer to the system-assigned identity or a resource ID to refer to a user-assigned identity.")

with self.argument_context('iot hub identity') as c:
c.argument('identities', options_list=['--identities'],
nargs='*', help="Accepts system or user assigned identities separated by spaces. Use '[system]'"
" to refer to the system-assigned identity or a resource ID to refer to a user-assigned identity.")

for subgroup in ['consumer-group', 'policy', 'certificate', 'routing-endpoint', 'route']:
with self.argument_context('iot hub {}'.format(subgroup)) as c:
Expand Down
6 changes: 6 additions & 0 deletions src/azure-cli/azure/cli/command_modules/iot/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ def load_command_table(self, _): # pylint: disable=too-many-statements
g.custom_show_command('show', 'iot_hub_consumer_group_get')
g.custom_command('delete', 'iot_hub_consumer_group_delete')

# iot hub identity commands
with self.command_group('iot hub identity', client_factory=iot_hub_service_factory) as g:
g.custom_command('assign', 'iot_hub_identity_assign')
g.custom_show_command('show', 'iot_hub_identity_show')
g.custom_command('remove', 'iot_hub_identity_remove')

# iot hub policy commands
with self.command_group('iot hub policy', client_factory=iot_hub_service_factory) as g:
g.custom_command('list', 'iot_hub_policy_list')
Expand Down
95 changes: 92 additions & 3 deletions src/azure-cli/azure/cli/command_modules/iot/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
EventHubProperties,
FailoverInput,
FeedbackProperties,
ManagedIdentity,
MessagingEndpointProperties,
OperationInputs,
EnrichmentProperties,
Expand Down Expand Up @@ -400,13 +401,15 @@ def iot_hub_create(cmd, client, hub_name, resource_group_name, location=None,
fileupload_sas_ttl=1,
fileupload_storage_authentication_type=None,
fileupload_storage_container_uri=None,
fileupload_storage_identity=None,
min_tls_version=None,
tags=None):
tags=None,
identities=None):
from datetime import timedelta
cli_ctx = cmd.cli_ctx
if enable_fileupload_notifications:
if not fileupload_storage_connectionstring or not fileupload_storage_container_name:
raise CLIError('Please specify storage endpoint(storage connection string and storage container name).')
raise CLIError('Please specify storage endpoint (storage connection string and storage container name).')
if fileupload_storage_connectionstring and not fileupload_storage_container_name:
raise CLIError('Please mention storage container name.')
if fileupload_storage_container_name and not fileupload_storage_connectionstring:
Expand All @@ -416,6 +419,9 @@ def iot_hub_create(cmd, client, hub_name, resource_group_name, location=None,
raise CLIError('Key-based authentication requires a connection string.')
if identity_based_file_upload and not fileupload_storage_container_uri:
raise CLIError('Identity-based authentication requires a storage container uri (--fileupload-storage-container-uri, --fcu).')
if not identity_based_file_upload and fileupload_storage_identity:
raise CLIError('In order to set a fileupload storage identity, please set file upload storage authentication (--fsa) to IdentityBased')

location = _ensure_location(cli_ctx, resource_group_name, location)
sku = IotHubSkuInfo(name=sku, capacity=unit)

Expand All @@ -437,7 +443,8 @@ def iot_hub_create(cmd, client, hub_name, resource_group_name, location=None,
connection_string=fileupload_storage_connectionstring if fileupload_storage_connectionstring else '',
container_name=fileupload_storage_container_name if fileupload_storage_container_name else '',
authentication_type=fileupload_storage_authentication_type if fileupload_storage_authentication_type else None,
container_uri=fileupload_storage_container_uri if fileupload_storage_container_uri else '')
container_uri=fileupload_storage_container_uri if fileupload_storage_container_uri else '',
identity=ManagedIdentity(fileupload_storage_identity) if fileupload_storage_identity else None)

properties = IotHubProperties(event_hub_endpoints=event_hub_dic,
messaging_endpoints=msg_endpoint_dic,
Expand All @@ -450,6 +457,16 @@ def iot_hub_create(cmd, client, hub_name, resource_group_name, location=None,
sku=sku,
properties=properties,
tags=tags)
if identities:
user_identities = [identity for identity in identities if identity != '[system]']
for identity in user_identities:
hub_description.identity.user_assigned_identities[identity] = {}

if '[system]' in identities:
hub_description.identity.type = "SystemAssigned, UserAssigned" if hub_description.identity.user_assigned_identities else "SystemAssigned"
else:
hub_description.identity.type = "UserAssigned"

return client.iot_hub_resource.begin_create_or_update(resource_group_name, hub_name, hub_description)


Expand Down Expand Up @@ -489,6 +506,7 @@ def update_iot_hub_custom(instance,
fileupload_sas_ttl=None,
fileupload_storage_authentication_type=None,
fileupload_storage_container_uri=None,
fileupload_storage_identity=None,
tags=None):
from datetime import timedelta
if tags is not None:
Expand Down Expand Up @@ -536,6 +554,14 @@ def update_iot_hub_custom(instance,
raise CLIError('Please mention storage connection string.')
if fileupload_sas_ttl is not None:
instance.properties.storage_endpoints['$default'].sas_ttl_as_iso8601 = timedelta(hours=fileupload_sas_ttl)

# If we are now (or will be) using fsa=identity AND we've set a new identity
if instance.properties.storage_endpoints['$default'].authentication_type == AuthenticationType.IdentityBased and fileupload_storage_identity:
# setup new fsi
instance.properties.storage_endpoints['$default'].identity = ManagedIdentity(fileupload_storage_identity)
# otherwise - let them know they need identity-based auth enabled
elif fileupload_storage_identity:
raise CLIError('In order to set a file upload storage identity, you must set the file upload storage authentication type (--fsa) to IdentityBased')
return instance


Expand Down Expand Up @@ -605,6 +631,69 @@ def iot_hub_consumer_group_delete(client, hub_name, consumer_group_name, resourc
return client.iot_hub_resource.delete_event_hub_consumer_group(resource_group_name, hub_name, event_hub_name, consumer_group_name)


def iot_hub_identity_assign(cmd, client, hub_name, identities, role=None, scopes=None, resource_group_name=None):
resource_group_name = _ensure_resource_group_name(client, resource_group_name, hub_name)
hub = iot_hub_get(cmd, client, hub_name, resource_group_name)

# if assigning a [system] identity, use role and scopes to update it after
user_identities = [identity for identity in identities if identity != '[system]']
for identity in user_identities:
hub.identity.user_assigned_identities[identity] = {}

if '[system]' in identities or 'SystemAssigned' in hub.identity.type:
hub.identity.type = "SystemAssigned, UserAssigned" if hub.identity.user_assigned_identities else "SystemAssigned"
else:
hub.identity.type = "UserAssigned" if hub.identity.user_assigned_identities else "None"

if '[system]' in identities:
if role and scopes:
# update hub
hub = client.iot_hub_resource.begin_create_or_update(resource_group_name, hub_name, hub, {'IF-MATCH': hub.etag})
# get hub identity

# system_identity = hub.identity.principalId

# setup scope and role for system_identity
return hub

return client.iot_hub_resource.begin_create_or_update(resource_group_name, hub_name, hub, {'IF-MATCH': hub.etag})


def iot_hub_identity_show(cmd, client, hub_name, resource_group_name=None):
resource_group_name = _ensure_resource_group_name(client, resource_group_name, hub_name)
hub = iot_hub_get(cmd, client, hub_name, resource_group_name)
return hub.identity

def iot_hub_identity_remove(cmd, client, hub_name, identities, resource_group_name=None):
resource_group_name = _ensure_resource_group_name(client, resource_group_name, hub_name)
hub = iot_hub_get(cmd, client, hub_name, resource_group_name)
hub_identity = hub.identity

# if identity is '[system]', turn off system managed identity
if '[system]' in identities:
if 'SystemAssigned' not in hub_identity.type:
raise CLIError('Hub {} is not currently using a System-assigned Identity'.format(hub_name))
hub_identity.type = "UserAssigned" if 'UserAssigned' in hub.identity.type else "None"

# separate user identities from system identity
user_identities = [identity for identity in identities if identity != '[system]']

# loop through user_identities to remove
for identity in user_identities:
if not hub_identity.user_assigned_identities[identity]:
raise CLIError('Hub {0} is not currently using a user-assigned identity with id: {1}'.format(hub_name, identity))
del hub_identity.user_assigned_identities[identity]

# assign identity type correctly
if 'SystemAssigned' in hub_identity.type:
hub_identity.type = 'SystemAssigned, UserAssigned' if hub_identity.user_assigned_identities else 'SystemAssigned'
else:
hub_identity.type = 'UserAssigned' if hub_identity.user_assigned_identities else 'None'

hub.identity = hub_identity
return client.iot_hub_resource.begin_create_or_update(resource_group_name, hub_name, hub, {'IF-MATCH': hub.etag})


def iot_hub_policy_list(client, hub_name, resource_group_name=None):
resource_group_name = _ensure_resource_group_name(client, resource_group_name, hub_name)
return client.iot_hub_resource.list_keys(resource_group_name, hub_name)
Expand Down