Skip to content

Conversation

@bim-msft
Copy link
Contributor

@bim-msft bim-msft commented Feb 6, 2020

Support for #11038
Bump the Key Vault mgmt-plane SDK version to 2.1.1 (This is the fixed version, 2.1.0 is buggy)

Add two command groups, all of them are marked as preview:

  1. az keyvault private-endpoint: manage vault private endpoint connections.
  2. az keyvault private-link-resource: manage vault private link resources.

Whole scenario and test instructions:

  1. Prepare the resources: a Key Vault and a Virtual Network within the same region (preferred region: Central US EUAP).
  2. Disable private endpoint network policy for the new created vnet: https://docs.microsoft.com/en-us/azure/private-link/disable-private-endpoint-network-policy#using-azure-cli
  3. Create a private endpoint connection request via network command: network private-endpoint create -g {rg} -n {pe} --vnet-name {vnet} --subnet {subnet} -l {loc} --connection-name {pe_connection} --private-connection-resource-id {kv_id} --group-ids vault (The group-ids can be obtained from command az keyvault private-link-resource show, for Key Vault service, the group id is vault, I remember that @myronfanqiu planned to implement a new command in network group, which can be used to obtain the group id of all service types).
  4. Show the private endpoint connection on Key Vault side: keyvault private-endpoint show --connection-id {kv_pe_id}.
  5. Approve or reject this connection request: keyvault private-endpoint approve -n {kv} --connection-name {kv_pe_name} --approval-description "{approval_desc}", keyvault private-endpoint reject --connection-id {kv_pe_id} --rejection-description "{rejection_desc}"

This checklist is used to make sure that common guidelines for a pull request are followed.

@bim-msft
Copy link
Contributor Author

bim-msft commented Feb 7, 2020

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

if not connection_id:
if not all([connection_name, vault_name]):
raise argparse.ArgumentError(
None, 'specify both: --connection-name and --vault-name')
Copy link
Member

Choose a reason for hiding this comment

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

In az keyvault private-endpoint show -h, it should be --name instead of --vault-name.

Suggested change
None, 'specify both: --connection-name and --vault-name')
None, 'specify both: --connection-name and --name')

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jiasli I prefer to replace all --name to --vault-name as this is consistent with other subgroup like az keyvault key, for the subgroup, --name/-n should represent the name of the sub resource itself (key, secret, private-endpoint), the name of vault should be represented by --vault-name.
How do you think?

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense. In that case, it should be --vault-name here:

c.argument('vault_name', vault_name_type, options_list=['--name', '-n'], required=False,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jiasli Yea, I will change it.

Comment on lines +167 to +169
helps['keyvault private-link-resource show'] = """
type: command
short-summary: Show the private link resources supported for a Key Vault.
Copy link
Member

Choose a reason for hiding this comment

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

c.argument('group_ids', nargs='+', help='The ID(s) of the group(s) obtained from the remote resource that this private endpoint should connect to. You can use "az keyvault(storage/etc) private-endpoint show" to obtain the list of group ids.')

The az network private-endpoint create -h's help message doesn't conform to this command name. @myronfanqiu

retries = 0
while self.cmd('keyvault private-endpoint show --connection-id {kv_pe_id}').\
get_output_in_json()['provisioningState'] != 'Succeeded' or retries > max_retries:
time.sleep(5)
Copy link
Member

Choose a reason for hiding this comment

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

Better to sleep only during live run:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea

Comment on lines 124 to 128
self.cmd('keyvault private-endpoint approve -n {kv} --connection-name {kv_pe_name} '
'--approval-description "{approval_desc}"', checks=[
self.check('privateLinkServiceConnectionState.status', 'Approved'),
self.check('privateLinkServiceConnectionState.description', '{approval_desc}')
])
Copy link
Member

Choose a reason for hiding this comment

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

Let's check provisioningState in the return value as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, will add this.

Comment on lines +85 to +88
g.custom_command('approve', 'approve_private_endpoint_connection',
validator=validate_private_endpoint_connection_id)
g.custom_command('reject', 'reject_private_endpoint_connection',
validator=validate_private_endpoint_connection_id)
Copy link
Member

@jiasli jiasli Feb 11, 2020

Choose a reason for hiding this comment

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

approve and reject are not common CLI commands. An alternative ways may be putting them in keyvault private-endpoint update --status approved/rejected. Has this been confirmed with PowerShell team @isra-fel or Key Vault PM?

It is not very conventional for PowerShell to design corresponding commands as Approve-AzKeyvaultPrivateEndpoint or Reject-AzKeyvaultPrivateEndpoint (in my mind).

Copy link
Contributor Author

@bim-msft bim-msft Feb 11, 2020

Choose a reason for hiding this comment

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

@jiasli Yes, this was confirmed with Key Vault team, will forward you the email later.

Copy link
Contributor

Choose a reason for hiding this comment

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

here. I think this design is good.

Comment on lines 1160 to 1164
def show_private_endpoint_connection(client, resource_group_name, vault_name, connection_name,
connection_id=None): # pylint: disable=unused-argument
"""Show details of a private endpoint connection associated with a Key Vault."""
return client.get(resource_group_name=resource_group_name, vault_name=vault_name,
private_endpoint_connection_name=connection_name)
Copy link
Member

Choose a reason for hiding this comment

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

If this is a 1:1 mapping, maybe we can eliminate the custom function?

Copy link
Contributor Author

@bim-msft bim-msft Feb 11, 2020

Choose a reason for hiding this comment

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

@jiasli The only thing I have to do here is to use name connection_name instead of private_endpoint_connection_name, because of this minor mismatch, I can not directly map it to SDK method, do you have any suggestion?

Copy link
Member

Choose a reason for hiding this comment

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

Let's use extra to attach parameters.

c.extra('identifier', options_list=['--id'], help='Id of the {}. If specified all other \'Id\' arguments should be omitted.'.format(item), validator=validate_vault_id(item))

tags=private_endpoint_connection.tags,
location=private_endpoint_connection.location,
private_link_service_connection_state=PrivateLinkServiceConnectionState(
status='Approved',
Copy link
Member

Choose a reason for hiding this comment

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

Let's not hard-code it but use the value in PrivateEndpointServiceConnectionStatus instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea, will refine this.

Comment on lines 1191 to 1192
tags=private_endpoint_connection.tags,
location=private_endpoint_connection.location,
Copy link
Member

Choose a reason for hiding this comment

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

According to the code of PrivateEndpointConnection, it seems tags and location will be discarded. Also, can we just modify the returned value of client.get?

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, makes sense, will refine this.

))


def reject_private_endpoint_connection(cmd, client, resource_group_name, vault_name, connection_name,
Copy link
Member

Choose a reason for hiding this comment

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

We'd better to extract the common code and call it with a switch.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea.

return client.put(resource_group_name=resource_group_name,
vault_name=vault_name,
private_endpoint_connection_name=connection_name,
private_endpoint=private_endpoint_connection.private_endpoint,
Copy link
Member

Choose a reason for hiding this comment

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

private_endpoint has been moved down to properties due to the parameter count change. This is caused by autorest's payload-flattening-threshold=2 config which will flatten the parameters when the parameter count <= 2.

Anyway, let's remove it.

@bim-msft bim-msft merged commit bb9c5f2 into Azure:dev Feb 11, 2020
@bim-msft bim-msft deleted the bim_kv_private_ep branch February 11, 2020 16:08
Comment on lines +147 to +150
helps['keyvault private-endpoint'] = """
type: group
short-summary: Manage vault private endpoint connections.
"""
Copy link
Member

Choose a reason for hiding this comment

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

On second thought, we'd better name it as private-endpoint-connection as it corresponds to privateEndpointConnections from az keyvault show.

    "privateEndpointConnections": [
      {
        "etag": "9fae19d5c0704012a6b0544574fe24d2",
        "id": "/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourceGroups/rg1/providers/Microsoft.KeyVault/vaults/kv0130/privateEndpointConnections/c9e56b4f661f4cf382aeb5d832bf6f9f",
        "privateEndpoint": {
          "id": "/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourceGroups/rg1/providers/Microsoft.Network/privateEndpoints/pe1",
          "resourceGroup": "rg1"
        },
        "privateLinkServiceConnectionState": {
          "actionRequired": null,
          "actionsRequired": "None",
          "description": "",
          "status": "Approved"
        },
        "provisioningState": "Succeeded",
        "resourceGroup": "rg1"
      }

privateEndpoint stands for another resource type Microsoft.Network/privateEndpoints. I think we shouldn't mix these two concepts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jiasli Thanks for this, for the convenience, I shortened the group name as private-endpoint (in fact, I copied the group name from network private-endpoint), but as you mentioned, this name stands for another resource type and may cause confusion, I will modify this later.


if not connection_id:
if not all([connection_name, vault_name]):
raise argparse.ArgumentError(
Copy link
Contributor

Choose a reason for hiding this comment

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

Based on my knowledge, usually we would raise CLIError('usage error:'). We can discuss.

Comment on lines +85 to +88
g.custom_command('approve', 'approve_private_endpoint_connection',
validator=validate_private_endpoint_connection_id)
g.custom_command('reject', 'reject_private_endpoint_connection',
validator=validate_private_endpoint_connection_id)
Copy link
Contributor

Choose a reason for hiding this comment

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

here. I think this design is good.

min_api='2018-02-14',
client_factory=keyvault_client_private_link_resources_factory,
is_preview=True) as g:
g.show_command('show', 'list_by_vault')
Copy link
Contributor

Choose a reason for hiding this comment

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

should it support id?

self.check('provisioningState', 'Updating')
])

max_retries = 20
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is because of the errors of the swagger spec. Could we add some comments here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants