Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure IoT CA functionality #4804

Merged
merged 4 commits into from
Nov 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions azure-cli.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,10 @@
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\mgmt_iot_hub_device\lib\__init__.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\mgmt_iot_hub_device\__init__.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\sas_token_auth.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\tests\test_iot_certificate_commands.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\tests\test_iot_commands.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\tests\test_sas_token_auth.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\_constants.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\_factory.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\_help.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\_params.py" />
Expand Down
2 changes: 2 additions & 0 deletions azure-cli2017.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,10 @@
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\mgmt_iot_hub_device\lib\version.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\mgmt_iot_hub_device\lib\__init__.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\sas_token_auth.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\tests\test_iot_certificate_commands.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\tests\test_iot_commands.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\tests\test_sas_token_auth.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\_constants.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\_factory.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\_help.py" />
<Compile Include="command_modules\azure-cli-iot\azure\cli\command_modules\iot\_params.py" />
Expand Down
4 changes: 4 additions & 0 deletions src/command_modules/azure-cli-iot/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Certificate files
*.key
*.cer
*.pem
2 changes: 1 addition & 1 deletion src/command_modules/azure-cli-iot/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ Release History

0.1.14
++++++
* Adds support for certificate authorities (CA) and certificate chains.
* Minor fixes.

0.1.13
++++++
* minor fixes


0.1.12 (2017-09-22)
+++++++++++++++++++
* minor fixes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

certificate_help = """For a detailed explanation of CA certificates in Azure IoT Hub,
see https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-x509ca-overview """
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
def iot_hub_service_factory(_):
from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.mgmt.iothub.iot_hub_client import IotHubClient
return get_mgmt_service_client(IotHubClient).iot_hub_resource
return get_mgmt_service_client(IotHubClient)


def resource_service_factory(**_):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# --------------------------------------------------------------------------------------------

from azure.cli.core.help_files import helps
from ._constants import certificate_help

helps['iot'] = """
type: group
Expand All @@ -20,10 +21,97 @@
short-summary: (PREVIEW) Manage Azure IoT hubs.
"""

helps['iot hub certificate'] = """
type: group
short-summary: Manage IoT Hub certificates.
"""

helps['iot hub certificate create'] = """
type: command
short-summary: Create/upload an Azure IoT Hub certificate.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this command iot hub certificate create when --path to file containing the certificate is required?
Looks like this should be iot hub certificate upload?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit strange. The command creates a Certificate object in a users IoT Hub. One of the parameters for creation is a Unicode string that represents the certificate. It's not truly uploading a file, but rather we are extracting the file contents if it's valid Unicode and using that as the "certificate" parameter, or base64 encoding the contents and using that string as the param. Additionally, we were trying to keep command name parity with the other operations we own.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I understand.

long-summary: {0}
examples:
- name: Uploads a CA certificate PEM file to an IoT hub.
text: >
az iot hub certificate create --hub-name MyIotHub --name MyCertificate --path /certificates/Certificate.pem
- name: Uploads a CA certificate CER file to an IoT hub.
text: >
az iot hub certificate create --hub-name MyIotHub --name MyCertificate --path /certificates/Certificate.cer
""".format(certificate_help)

helps['iot hub certificate update'] = """
type: command
short-summary: Update an Azure IoT Hub certificate.
long-summary: Uploads a new certificate to replace the existing certificate with the same name. {0}
examples:
- name: Updates a CA certificate in an IoT hub by uploading a new PEM file.
text: >
az iot hub certificate update --hub-name MyIotHub --name MyCertificate --path /certificates/NewCertificate.pem --etag
AAAAAAAAAAA=
- name: Updates a CA certificate in an IoT hub by uploading a new CER file.
text: >
az iot hub certificate update --hub-name MyIotHub --name MyCertificate --path /certificates/NewCertificate.cer --etag
AAAAAAAAAAA=
""".format(certificate_help)

helps['iot hub certificate delete'] = """
type: command
short-summary: Deletes an Azure IoT Hub certificate.
long-summary: {0}
examples:
- name: Deletes MyCertificate
text: >
az iot hub certificate delete --hub-name MyIotHub --name MyCertificate --etag AAAAAAAAAAA=
""".format(certificate_help)

helps['iot hub certificate show'] = """
type: command
short-summary: Shows information about a particular Azure IoT Hub certificate.
long-summary: {0}
examples:
- name: Show details about MyCertificate
text: >
az iot hub certificate show --hub-name MyIotHub --name MyCertificate
""".format(certificate_help)

helps['iot hub certificate list'] = """
type: command
short-summary: Lists all certificates contained within an Azure IoT Hub
long-summary: {0}
examples:
- name: List all certificates in MyIotHub
text: >
az iot hub certificate list --hub-name MyIotHub
""".format(certificate_help)

helps['iot hub certificate generate-verification-code'] = """
type: command
short-summary: Generates a verification code for an Azure IoT Hub certificate.
long-summary: This verification code is used to complete the proof of possession step for a certificate. Use this
verification code as the CN of a new certificate signed with the root certificates private key. {0}
examples:
- name: Generates a verification code for MyCertificate
text: >
az iot hub certificate generate-verification-code --hub-name MyIotHub --name MyCertificate --etag
AAAAAAAAAAA=
""".format(certificate_help)

helps['iot hub certificate verify'] = """
type: command
short-summary: Verifies an Azure IoT Hub certificate.
long-summary: Verifies a certificate by uploading a verification certificate containing the verification code obtained
by calling generate-verification-code. This is the last step in the proof of possession process. {0}
examples:
- name: Verifies ownership of the MyCertificate private key.
text: >
az iot hub certificate verify --hub-name MyIotHub --name MyCertificate --path /certificates/Verification.pem --etag
AAAAAAAAAAA=
""".format(certificate_help)

helps['iot hub create'] = """
type: command
short-summary: Create an Azure IoT hub.
long-summary: 'For an introduction to Azure IoT Hub, see https://docs.microsoft.com/azure/iot-hub/'
long-summary: For an introduction to Azure IoT Hub, see https://docs.microsoft.com/azure/iot-hub/
examples:
- name: Create an IoT Hub with the free pricing tier F1, in the region of the resource group.
text: >
Expand Down Expand Up @@ -288,11 +376,11 @@
helps['iot device export'] = """
type: command
short-summary: Export all the device identities in the IoT hub identity registry to an Azure Storage blob container.
long-summary: 'For more information, see https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry#import-and-export-device-identities'
long-summary: For more information, see https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry#import-and-export-device-identities
"""

helps['iot device import'] = """
type: command
short-summary: Import, update, or delete device identities in the IoT hub identity registry from a blob.
long-summary: 'For more information, see https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry#import-and-export-device-identities'
long-summary: For more information, see https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry#import-and-export-device-identities
"""
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from azure.cli.core.commands.parameters import (location_type, enum_choice_list,
from argcomplete.completers import FilesCompleter
from azure.cli.core.commands.parameters import (location_type, enum_choice_list, file_type,
get_resource_name_completion_list, CliArgumentType)
from azure.cli.core.commands import register_cli_argument
from azure.mgmt.iothub.models.iot_hub_client_enums import IotHubSku
Expand All @@ -23,16 +24,30 @@ def get_device_id_completion_list(prefix, action, parsed_args,
completer=get_resource_name_completion_list('Microsoft.Devices/IotHubs'),
help='IoT Hub name.')

register_cli_argument('iot hub', 'hub_name', hub_name_type, options_list=('--name', '-n'),
id_part='name')
for subgroup in ['consumer-group', 'policy', 'job']:
etag_type = CliArgumentType(
None, help='Entity Tag (etag) of the object.')


register_cli_argument('iot hub', 'hub_name', hub_name_type, options_list=('--name', '-n'), id_part='name')

register_cli_argument('iot hub', 'etag', etag_type, options_list=('--etag', '-e'))

for subgroup in ['consumer-group', 'policy', 'job', 'certificate']:
register_cli_argument('iot hub {}'.format(subgroup), 'hub_name', options_list=('--hub-name',))

register_cli_argument('iot device', 'hub_name', hub_name_type)

register_cli_argument('iot', 'device_id', options_list=('--device-id', '-d'), help='Device Id.',
completer=get_device_id_completion_list)

# Arguments for 'iot hub certificate' group
register_cli_argument('iot hub certificate', 'certificate_path', options_list=('--path', '-p'), type=file_type,
completer=FilesCompleter([".cer", ".pem"]),
help='The path to the file containing the certificate.')

register_cli_argument('iot hub certificate', 'certificate_name', options_list=('--name', '-n'),
help='A friendly name for the certificate.')

# Arguments for 'iot hub consumer-group' group
register_cli_argument('iot hub consumer-group', 'consumer_group_name',
options_list=('--name', '-n'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# --------------------------------------------------------------------------------------------

from os.path import exists, join
import base64
from OpenSSL import crypto


Expand Down Expand Up @@ -37,3 +38,15 @@ def create_self_signed_certificate(device_id, valid_days, cert_output_dir):
'privateKey': key_dump,
'thumbprint': thumbprint
}


def open_certificate(certificate_path):
certificate = ""
if certificate_path.endswith('.pem') or certificate_path.endswith('.cer'):
with open(certificate_path, "rb") as cert_file:
certificate = cert_file.read()
try:
certificate = certificate.decode("utf-8")
except UnicodeError:
certificate = base64.b64encode(certificate).decode("utf-8")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm, we don't want to encode the certificate with base64 if all the characters are valid unicode?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's correct.

return certificate
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ def __call__(self, poller):
raise e
return None

# iot hub certificate commands
cli_command(__name__, 'iot hub certificate list', custom_path.format('iot_hub_certificate_list'),
factory)
cli_command(__name__, 'iot hub certificate show', custom_path.format('iot_hub_certificate_get'),
factory)
cli_command(__name__, 'iot hub certificate create', custom_path.format('iot_hub_certificate_create'),
factory)
cli_command(__name__, 'iot hub certificate delete', custom_path.format('iot_hub_certificate_delete'),
factory)
cli_command(__name__, 'iot hub certificate generate-verification-code',
custom_path.format('iot_hub_certificate_gen_code'), factory)
cli_command(__name__, 'iot hub certificate verify', custom_path.format('iot_hub_certificate_verify'),
factory)
cli_command(__name__, 'iot hub certificate update', custom_path.format('iot_hub_certificate_update'),
factory)

# iot hub commands
cli_command(__name__, 'iot hub create', custom_path.format('iot_hub_create'), factory)
cli_command(__name__, 'iot hub list', custom_path.format('iot_hub_list'), factory)
Expand Down
Loading