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

[Feature] To be able to rotate subscription key #7596

Merged
merged 15 commits into from
Jan 28, 2020

Conversation

mssfang
Copy link
Member

@mssfang mssfang commented Jan 22, 2020

Add the ability to rotate the subscription key.
In addition, increase test coverage to TextAnalyticsClientBuilder.

Fixes: #7390

@mssfang mssfang added Client This issue points to a problem in the data-plane of the library. TextAnalytics labels Jan 22, 2020
@mssfang mssfang added this to the [2020] February milestone Jan 22, 2020
@mssfang mssfang self-assigned this Jan 22, 2020
@mssfang mssfang marked this pull request as ready for review January 22, 2020 07:07
Copy link
Member

@JonathanGiles JonathanGiles left a comment

Choose a reason for hiding this comment

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

From a Java point of view, this all looks fine. I would like @g2vinay and @schaabs to weigh in on how this fits into their vision for auth and identity before this is made public API, though.

* @param subscriptionKey the subscription key
* @return the {@link TextAnalyticsSubscriptionKeyCredential} itself
*/
public TextAnalyticsSubscriptionKeyCredential updateCredential(String subscriptionKey) {
Copy link
Member

Choose a reason for hiding this comment

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

Don't think returning TextAnalyticsSubscriptionKeyCredential is necessary here. Returning void should be sufficient.

Copy link
Member

Choose a reason for hiding this comment

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

I am not sure if we agreed on the terminology here in previous arch-board review - there were several proposals refresh, update, set, rotate etc.

* @param subscriptionKey the subscription key
* @return the {@link TextAnalyticsSubscriptionKeyCredential} itself
*/
public TextAnalyticsSubscriptionKeyCredential updateCredential(String subscriptionKey) {
Copy link
Member

Choose a reason for hiding this comment

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

Also, when is this method called? Is this method expected to be called by the user when they want to update the key? If so, it would be good to include in samples and code snippets.

Copy link
Member Author

Choose a reason for hiding this comment

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

I will add the samples and snippet.

package com.azure.ai.textanalytics.models;

/**
* Subscription key credential that shared across cognitive services, or restrict to single service.
Copy link
Member

Choose a reason for hiding this comment

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

Is this applicable for all cognitive services? If so, is the plan to duplicate this credential in all cognitive services modules or would we create a common module like storage has to put the common stuff there?

Copy link
Member Author

Choose a reason for hiding this comment

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

We had a discussion about having a common module. We decided not to have a common module now because currently we only have one service implemented. We don't really know the use case.

Copy link
Member

Choose a reason for hiding this comment

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

@mssfang is right - this is still an open question. We're starting to look at FormRecognizer now, though, so we'll start driving the "where would we put a common Cognitive credential" with the architects.

* @return the {@link TextAnalyticsSubscriptionKeyCredential} itself
*/
public TextAnalyticsSubscriptionKeyCredential updateCredential(String subscriptionKey) {
this.subscriptionKey = subscriptionKey;
Copy link
Member

Choose a reason for hiding this comment

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

Can subscriptionKey be null or empty? If not, you may want to check for these conditions here and in the constructor.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed. Will add the check

* @return the {@link TextAnalyticsSubscriptionKeyCredential} itself
*/
public TextAnalyticsSubscriptionKeyCredential updateCredential(String subscriptionKey) {
this.subscriptionKey = subscriptionKey;
Copy link
Member

Choose a reason for hiding this comment

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

Is this thread safe? Is there a way to guarantee that when modified it updates everywhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

I had a few discussions on the thread-safe concern. some believe it is thread-safe. the reason is it is a single atomic assignment. But depends on how you use it, It could be not threaded safe. This is one I am not sure yet. I will give you an update once finalized.

Copy link
Member

Choose a reason for hiding this comment

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

In the pipeline policy, it is fetched, so it's possible that the policy picks up a different value than the one that is set. This is not thread safe.

@g2vinay
Copy link
Member

g2vinay commented Jan 24, 2020

Looking at the

From a Java point of view, this all looks fine. I would like @g2vinay and @schaabs to weigh in on how this fits into their vision for auth and identity before this is made public API, though.

Looking at the authentication model for text analytics, a subscription key is passed via header and that's it (it acts as the access token).
TLS encryption will be applied during network calls so subscription key can't be easily intercepted.
Its worth to ensure/add the check in the code that the resource endpoint we're hitting starts with 'https', to ensure TLS protocol comes into play during network calls.

Currently, in Azure Identity there is no support to rotate any of the credentials it supports. The credential needs to be restarted.
In this PR too, the rotation process is manual for the user via the update call on the subscription key credential. So, that looks fine to me.

@JonathanGiles
Copy link
Member

Currently, in Azure Identity there is no support to rotate any of the credentials it supports. The credential needs to be restarted.
In this PR too, the rotation process is manual for the user via the update call on the subscription key credential. So, that looks fine to me.

This was the main point of my request - I do not want this API to be evolving separately than azure-identity intends to evolve, and would therefore like consideration about whether there is any reconciliation that needs to go on here.

* @return the {@link TextAnalyticsSubscriptionKeyCredential} itself
*/
public TextAnalyticsSubscriptionKeyCredential updateCredential(String subscriptionKey) {
this.subscriptionKey = subscriptionKey;
Copy link
Member

Choose a reason for hiding this comment

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

In the pipeline policy, it is fetched, so it's possible that the policy picks up a different value than the one that is set. This is not thread safe.

@conniey
Copy link
Member

conniey commented Jan 24, 2020

This was the main point of my request - I do not want this API to be evolving separately than azure-identity intends to evolve, and would therefore like consideration about whether there is any reconciliation that needs to go on here.

I think it would be better to have a rotating credential (either manual or on some cadence, etc.) of sorts in azure-identity. We want to support rotating credentials in Event Hubs, too.

@annelo-msft
Copy link
Member

Looking at the authentication model for text analytics, a subscription key is passed via header and that's it (it acts as the access token).
TLS encryption will be applied during network calls so subscription key can't be easily intercepted.

Some of the other cognitive services support getting a bearer token from an STS in addition to passing the subscription key. TextAnalytics doesn't currently support this, which is part of why we're scoping this type to TA-only.

@mssfang mssfang requested a review from anuchandy January 27, 2020 17:37
.subscriptionKey("{subscription_key}")
.endpoint("https://{servicename}.cognitiveservices.azure.com/")
.subscriptionKey(new TextAnalyticsSubscriptionKeyCredential("{subscription_key}"))
.endpoint("{endpoint}")
Copy link
Member

Choose a reason for hiding this comment

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

Why the change to {endpoint}? It is more clear what the string should look like with the last change.

Copy link
Member Author

Choose a reason for hiding this comment

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

Based on what Mariana point out here: #7596 (comment)

The subscription key could apply to both Cognitive Subscription Key or Text Analytics Subscription key.

public void nullAADCredential() {
assertThrows(NullPointerException.class, () -> {
final TextAnalyticsClientBuilder builder = new TextAnalyticsClientBuilder();
builder.endpoint(getEndpoint()).credential(null).buildClient();
Copy link
Member

Choose a reason for hiding this comment

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

Generally, you try to limit the scope of your assertion. How do you know it threw in credential(null) and not buildclient()?

This goes for all the other tests that do the same.

// arrange
final TextAnalyticsClientBuilder builder = new TextAnalyticsClientBuilder();

// Act & Assert
assertThrows(NullPointerException.class, () -> builder.credential(null));

Copy link
Member Author

Choose a reason for hiding this comment

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

Make sense. I will update it.


<!-- embedme ./src/samples/java/com/azure/ai/textanalytics/ReadmeSamples.java#L174-L180 -->
```java
TextAnalyticsSubscriptionKeyCredential credential = new TextAnalyticsSubscriptionKeyCredential("{expired_subscription_key}");
Copy link
Member

Choose a reason for hiding this comment

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

I wouldn't call it expired_subscription_key as it might give the wrong message to people when creating the client.
it could be just subscription_key, and leave new_subscription_key

Copy link
Member

@maririos maririos left a comment

Choose a reason for hiding this comment

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

For changes related to rotate subscription key LGTM.

@mssfang mssfang requested a review from conniey January 28, 2020 04:38
@mssfang mssfang merged commit 980616d into Azure:master Jan 28, 2020
@mssfang mssfang deleted the RotateSubscriptionKey branch January 28, 2020 22:10
@JonathanGiles
Copy link
Member

JonathanGiles commented Jan 29, 2020

I asked for this to be reviewed and approved by @g2vinay or @schaabs from an identity perspective, but I don't see that approval on this PR. Has this been done?

Edit: I see @g2vinay commented further up.

@mssfang
Copy link
Member Author

mssfang commented Jan 29, 2020

@JonathanGiles Sorry. No for your question. I will follow up with vinay and scott for further improvement and open a new PR if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Client This issue points to a problem in the data-plane of the library. Cognitive - Text Analytics
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add ability to rotate subscription keys for Text Analytics service
9 participants