Skip to content

Commit 81372d0

Browse files
authored
[KeyVault] KeyVault Round 3 Commands (Azure#1215)
* Key backup/restore/import. Certificate import. Pending certificate operations. * Fix build errors and help text. * Code review fix.
1 parent fd5cfec commit 81372d0

26 files changed

+2181
-827
lines changed

azure-cli.pyproj

+4-56
Original file line numberDiff line numberDiff line change
@@ -74,33 +74,23 @@
7474
<Compile Include="azure-cli\setup.py" />
7575
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\credential.py" />
7676
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\custom.py" />
77-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\container_registry.py" />
77+
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\container_registry_management_client.py" />
7878
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\credentials.py" />
7979
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\exceptions.py" />
8080
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry.py" />
81-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_create_parameters.py" />
8281
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_credentials.py" />
83-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_move_request.py" />
8482
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_name_check_request.py" />
8583
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_name_status.py" />
86-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_properties.py" />
87-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_properties_create_parameters.py" />
84+
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_paged.py" />
8885
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_update_parameters.py" />
89-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\resource_list_registry.py" />
90-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\storage_account_base_properties.py" />
86+
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\resource.py" />
9187
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\storage_account_properties.py" />
92-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\subscription_notification.py" />
93-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\subscription_properties.py" />
9488
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__init__.py" />
95-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\operation.py" />
96-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\registries.py" />
97-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\subscriptions.py" />
89+
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\registries_operations.py" />
9890
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\__init__.py" />
9991
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\version.py" />
10092
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\__init__.py" />
10193
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\repository.py" />
102-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\storage.py" />
103-
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\_arm_utils.py" />
10494
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\_constants.py" />
10595
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\_factory.py" />
10696
<Compile Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\_format.py" />
@@ -729,9 +719,7 @@
729719
<Folder Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\" />
730720
<Folder Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\" />
731721
<Folder Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\" />
732-
<Folder Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\" />
733722
<Folder Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\" />
734-
<Folder Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\__pycache__\" />
735723
<Folder Include="command_modules\azure-cli-acs\" />
736724
<Folder Include="command_modules\azure-cli-acs\azure\" />
737725
<Folder Include="command_modules\azure-cli-acs\azure\cli\" />
@@ -911,46 +899,6 @@
911899
<Content Include="azure-cli-core\setup.cfg" />
912900
<Content Include="azure-cli\az.completion.sh" />
913901
<Content Include="azure-cli\setup.cfg" />
914-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry.pyc" />
915-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_create_parameters.pyc" />
916-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_credentials.pyc" />
917-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_move_request.pyc" />
918-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_name_check_request.pyc" />
919-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_name_status.pyc" />
920-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_properties.pyc" />
921-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_properties_create_parameters.pyc" />
922-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\registry_update_parameters.pyc" />
923-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\resource_list_registry.pyc" />
924-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\storage_account_base_properties.pyc" />
925-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\storage_account_properties.pyc" />
926-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\subscription_notification.pyc" />
927-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\subscription_properties.pyc" />
928-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__init__.pyc" />
929-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\registry.cpython-35.pyc" />
930-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\registry_create_parameters.cpython-35.pyc" />
931-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\registry_credentials.cpython-35.pyc" />
932-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\registry_move_request.cpython-35.pyc" />
933-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\registry_name_check_request.cpython-35.pyc" />
934-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\registry_name_status.cpython-35.pyc" />
935-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\registry_properties.cpython-35.pyc" />
936-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\registry_properties_create_parameters.cpython-35.pyc" />
937-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\registry_update_parameters.cpython-35.pyc" />
938-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\resource_list_registry.cpython-35.pyc" />
939-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\storage_account_base_properties.cpython-35.pyc" />
940-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\storage_account_properties.cpython-35.pyc" />
941-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\subscription_notification.cpython-35.pyc" />
942-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\subscription_properties.cpython-35.pyc" />
943-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\models\__pycache__\__init__.cpython-35.pyc" />
944-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\operation.pyc" />
945-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\registries.pyc" />
946-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\subscriptions.pyc" />
947-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\__init__.pyc" />
948-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\__pycache__\operation.cpython-35.pyc" />
949-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\__pycache__\registries.cpython-35.pyc" />
950-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\__pycache__\subscriptions.cpython-35.pyc" />
951-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\mgmt_acr\operations\__pycache__\__init__.cpython-35.pyc" />
952-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\template.existing.json" />
953-
<Content Include="command_modules\azure-cli-acr\azure\cli\command_modules\acr\template.new.json" />
954902
<Content Include="command_modules\azure-cli-acr\requirements.txt" />
955903
<Content Include="command_modules\azure-cli-acs\requirements.txt" />
956904
<Content Include="command_modules\azure-cli-component\requirements.txt" />

azure-cli.sln

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio 14
4-
VisualStudioVersion = 14.0.24720.0
4+
VisualStudioVersion = 14.0.25420.1
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "azure-cli", "azure-cli.pyproj", "{938454F7-93BD-41A7-84B2-3C89D64B969D}"
77
EndProject

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ paramiko==2.0.2
88
pip
99
pygments==2.1.3
1010
pylint==1.5.4
11+
pyOpenSSL==16.1.0
1112
pyyaml==3.11
1213
requests==2.9.1
1314
six==1.10.0

src/azure-cli-core/azure/cli/core/commands/_introspection.py

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def extract_full_summary_from_signature(operation):
1717
summary = lines[:match.regs[0][0]]
1818
else:
1919
summary = lines
20+
summary = summary.replace('\n', ' ').replace('\r', '')
2021
return summary
2122

2223
def _option_descriptions(operation):

src/command_modules/azure-cli-keyvault/azure/cli/command_modules/keyvault/_command_type.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import base64
77

88
from msrest.paging import Paged
9-
from msrest.exceptions import ValidationError
9+
from msrest.exceptions import ValidationError, ClientRequestError
1010
from msrestazure.azure_operation import AzureOperationPoller
1111

1212
from azure.cli.core.commands import command_table, CliCommand, LongRunningOperation
@@ -78,6 +78,11 @@ def get_token(server, resource, scope): # pylint: disable=unused-argument
7878
raise CLIError(ex.inner_exception.error.message)
7979
except AttributeError:
8080
raise CLIError(ex)
81+
except ClientRequestError as ex:
82+
if 'Failed to establish a new connection' in str(ex.inner_exception):
83+
raise CLIError('Max retries exceeded attempting to connect to vault. '
84+
'Try flushing your DNS cache or try again later.')
85+
raise CLIError(ex)
8186

8287
name = ' '.join(name.split())
8388
cmd = CliCommand(name, _execute_command, table_transformer=table_transformer)

src/command_modules/azure-cli-keyvault/azure/cli/command_modules/keyvault/_help.py

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@
5454
short-summary: Manage certificates.
5555
"""
5656

57+
helps['keyvault certificate pending'] = """
58+
type: group
59+
short-summary: Manage pending certificate creation operations.
60+
"""
61+
5762
helps['keyvault certificate contact'] = """
5863
type: group
5964
short-summary: Manage contacts for certificate management.

src/command_modules/azure-cli-keyvault/azure/cli/command_modules/keyvault/_params.py

+21-4
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,23 @@
2020
from azure.cli.command_modules.keyvault.keyvaultclient.generated.models import \
2121
(KeyAttributes, SecretAttributes, CertificateAttributes)
2222
from azure.cli.command_modules.keyvault._validators import \
23-
(datetime_type,
23+
(datetime_type, base64_encoded_certificate_type,
2424
get_attribute_validator,
2525
vault_base_url_type, validate_key_import_source,
2626
validate_key_type, validate_key_ops, validate_policy_permissions,
27-
validate_principal, validate_resource_group_name)
27+
validate_principal, validate_resource_group_name,
28+
validate_x509_certificate_chain,
29+
process_certificate_cancel_namespace)
2830

2931
# CUSTOM CHOICE LISTS
3032

3133
key_permission_values = ', '.join([x.value for x in KeyPermissions])
3234
secret_permission_values = ', '.join([x.value for x in SecretPermissions])
3335
certificate_permission_values = ', '.join([x.value for x in CertificatePermissions])
3436
json_web_key_op_values = ', '.join([x.value for x in JsonWebKeyOperation])
37+
secret_file_encoding_values = ['utf8', 'utf16le', 'ucs2', 'ascii']
38+
secret_file_decoding_values = ['base64', 'hex']
39+
certificate_file_encoding_values = ['base64']
3540

3641
# KEY ATTRIBUTE PARAMETER REGISTRATION
3742

@@ -87,6 +92,10 @@ def register_attributes_argument(scope, name, attr_class, create=False):
8792
register_cli_argument('keyvault key import', 'pem_password', help='Password of PEM file.', arg_group='Key Source')
8893
register_cli_argument('keyvault key import', 'byok_file', help='BYOK file containing the key to be imported. Must not be password protected.', arg_group='Key Source')
8994

95+
register_cli_argument('keyvault key backup', 'file_path', options_list=('--file', '-f'), help='Local file path in which to store key backup.')
96+
97+
register_cli_argument('keyvault key restore', 'file_path', options_list=('--file', '-f'), help='Local key backup from which to restore key.')
98+
9099
register_attributes_argument('keyvault key set-attributes', 'key', KeyAttributes)
91100

92101
register_cli_argument('keyvault secret', 'secret_version', options_list=('--version', '-v'), help='The secret version. If omitted, uses the latest version.', default='', required=False)
@@ -96,11 +105,19 @@ def register_attributes_argument(scope, name, attr_class, create=False):
96105

97106
register_cli_argument('keyvault certificate', 'certificate_version', options_list=('--version', '-v'), help='The certificate version. If omitted, uses the latest version.', default='', required=False)
98107
register_attributes_argument('keyvault certificate create', 'certificate', CertificateAttributes, True)
108+
register_attributes_argument('keyvault certificate import', 'certificate', CertificateAttributes, True)
99109
register_attributes_argument('keyvault certificate set-attributes', 'certificate', CertificateAttributes)
100-
for item in ['create', 'set-attributes']:
110+
for item in ['create', 'set-attributes', 'import']:
101111
register_cli_argument('keyvault certificate {}'.format(item), 'certificate_policy', options_list=('--policy', '-p'), help='JSON encoded policy defintion. Use @{file} to load from a file.', type=get_json_object)
102112

103-
register_cli_argument('keyvault certificate contact', 'contact_email', options_list=('--email',), help='Contact e-mail address. Must be unique within the vault.')
113+
register_cli_argument('keyvault certificate import', 'base64_encoded_certificate', options_list=('--file', '-f'), help='PKCS12 file or PEM file containing the certificate and private key.', type=base64_encoded_certificate_type)
114+
115+
register_cli_argument('keyvault certificate pending merge', 'x509_certificates', options_list=('--file', '-f'), help='File containing the certificate or certificate chain to merge.', validator=validate_x509_certificate_chain)
116+
register_attributes_argument('keyvault certificate pending merge', 'certificate', CertificateAttributes, True)
117+
118+
register_cli_argument('keyvault certificate pending cancel', 'cancellation_requested', ignore_type, validator=process_certificate_cancel_namespace)
119+
120+
register_cli_argument('keyvault certificate contact', 'contact_email', options_list=('--email',), help='Contact e-mail address. Must be unique.')
104121
register_cli_argument('keyvault certificate contact', 'contact_name', options_list=('--name',), help='Full contact name.')
105122
register_cli_argument('keyvault certificate contact', 'contact_phone', options_list=('--phone',), help='Contact phone number.')
106123

src/command_modules/azure-cli-keyvault/azure/cli/command_modules/keyvault/_validators.py

+32-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
#---------------------------------------------------------------------------------------------
55

66
import argparse
7+
import base64
8+
import binascii
79
from datetime import datetime
10+
import re
811

912
from azure.mgmt.keyvault import KeyVaultManagementClient
1013
from azure.mgmt.keyvault.models.key_vault_management_client_enums import \
@@ -22,6 +25,9 @@ def _extract_version(item_id):
2225

2326
# COMMAND NAMESPACE VALIDATORS
2427

28+
def process_certificate_cancel_namespace(namespace):
29+
namespace.cancellation_requested = True
30+
2531
# PARAMETER NAMESPACE VALIDATORS
2632

2733
def get_attribute_validator(name, attribute_class, create=False):
@@ -61,6 +67,8 @@ def validate_key_type(ns):
6167
'hsm': 'RSA-HSM'
6268
}
6369
ns.destination = dest_to_type_map[ns.destination]
70+
if ns.destination == 'RSA' and hasattr(ns, 'byok_file') and ns.byok_file:
71+
raise CLIError('BYOK keys are hardware protected. Omit --protection')
6472

6573
def validate_policy_permissions(ns):
6674
key_perms = ns.key_permissions
@@ -108,10 +116,33 @@ def validate_resource_group_name(ns):
108116
"The Resource 'Microsoft.KeyVault/vaults/{}'".format(vault_name) + \
109117
" not found within subscription")
110118

119+
def validate_x509_certificate_chain(ns):
120+
def _load_certificate_as_bytes(file_name):
121+
cert_list = []
122+
regex = r'-----BEGIN CERTIFICATE-----([^-]+)-----END CERTIFICATE-----'
123+
with open(file_name, 'r') as f:
124+
cert_data = f.read()
125+
for entry in re.findall(regex, cert_data):
126+
cert_list.append(base64.b64decode(entry.replace('\n', '')))
127+
return cert_list
128+
129+
ns.x509_certificates = _load_certificate_as_bytes(ns.x509_certificates)
130+
111131
# ARGUMENT TYPES
112132

133+
def base64_encoded_certificate_type(string):
134+
""" Loads file and outputs contents as base64 encoded string. """
135+
with open(string, 'rb') as f:
136+
cert_data = f.read()
137+
try:
138+
# for PEM files (including automatic endline conversion for Windows)
139+
cert_data = cert_data.decode('utf-8').replace('\r\n', '\n')
140+
except UnicodeDecodeError:
141+
cert_data = binascii.b2a_base64(cert_data).decode('utf-8')
142+
return cert_data
143+
113144
def datetime_type(string):
114-
''' Validates UTC datettime in format '%Y-%m-%d\'T\'%H:%M\'Z\''. '''
145+
""" Validates UTC datettime in format '%Y-%m-%d\'T\'%H:%M\'Z\''. """
115146
date_format = '%Y-%m-%dT%H:%MZ'
116147
return datetime.strptime(string, date_format)
117148

0 commit comments

Comments
 (0)