BatchPool - AuthenticationErrorDetail The specified type of authentication SharedKey is not allowed when external resources of type Network are linked - azure-batch-account

Getting error while creating Azure Batch Pool with private network configuration.
BatchClient bClient = BatchClient.Open(new BatchSharedKeyCredentials(batchUri, accountName, accountKey));
PoolSpecification poolSp = new PoolSpecification();
poolSp.NetworkConfiguration = new NetworkConfiguration
{
SubnetId = "/subscriptions/{0}/resourceGroups/{1}/providers/{2}/virtualNetworks/{3}/subnets/{4}"
};
Getting errors when creating job
await job.CommitAsync();
Exception: Microsoft.Azure.Batch.Protocol.Models.ErrorMessage - AuthenticationFailed
AuthenticationErrorDetail: The specified type of authentication SharedKey is not allowed when external resources of type Network are linked.

After research, I found that it is mandatory to use AAD authentication when using VNET. The reason is when using a shared key, the key doesn't have permission to access Network resources.
You can read the article mentioned in Authenticate Batch service solutions with Active Directory.

Related

Limit Scope to single file in Google Auth JWT client for Google service account

I'm am using a service account to generate an access token to access certain sheets in my google drive. That access token will be sent to the client-side user and using that users will access my sheets. But different users have access to different sheets and I want them to prevent access to other sheets with the same access token. Currently, the service account has access to all the file used by my app.
For generating access token I use googleapis's google.auth.JWT module. I use Firebase cloud functions as my backend with Node version 10
Here is my code,
try {
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
['https://www.googleapis.com/auth/drive',], // drive scope
);
const accessToken = await jwtClient.authorize();
} catch (error) {
console.log(error)
res.status(500).json(error)
}
Thanks in advance
If the permissions of the service account gives the token full access to every file in the folder these tokens would allow to read other documents too. I think you may workaround this granting a specific user permissions to a set of documents by changing the permissions of the file itself, instead of providing a generic access token. This page of the Drive documentation describes how to change permissions at a file level and provides some Node.js samples.

How can I authenticate against ADXProxy using app key authentication?

I am trying to access an Azure Application Insights resource via Redash, using the (preview) ADXProxy feature.
I've created an App Registration in Azure, and I've got some proof-of-concept python code which can successfully access my Application Insights resource and execute a Kusto query (traces | take 1) using an application token:
import azure.kusto
import azure.kusto.data.request
import msal
cluster = 'https://ade.applicationinsights.io/subscriptions/<MY_SUBSCRIPTION>/resourcegroups/<MY_RESOURCE_GROUP>/providers/microsoft.insights/components/<MY_APP_INSIGHTS_RESOURCE>'
app_id = '<MY_APP_ID>'
app_key = '<MY_SECRET>'
authority_id = '<MY_AAD_SUBSCRIPTION_ID>'
def run():
app = msal.ConfidentialClientApplication(
client_id=app_id,
client_credential=app_key,
authority='https://login.microsoftonline.com/<MY_AAD_SUBSCRIPTION_ID>')
token = app.acquire_token_for_client(['https://help.kusto.windows.net/.default'])
kcsb = azure.kusto.data.request.KustoConnectionStringBuilder.with_aad_application_token_authentication(
connection_string=cluster,
application_token=token['access_token']
)
client = azure.kusto.data.request.KustoClient(kcsb)
result = client.execute('<MY_APP_INSIGHTS_RESOURCE>', 'traces | take 1')
for res in result.primary_results:
print(res)
return 1
if __name__ == "__main__":
run()
However, Redash doesn't support application token authentication: it uses application key authentication, making a call like:
kcsb = azure.kusto.data.request.KustoConnectionStringBuilder.with_aad_application_key_authentication(
connection_string = cluster,
aad_app_id = app_id,
app_key = app_key,
authority_id = '<MY_AAD_SUBSCRIPTION_ID>'
)
I can't successfully connect to my App Insights resource using this type of flow. If I substitute this KustoConnectionStringBuilder into my program above, I get an exception telling me:
The resource principal named https://ade.applicationinsights.io was not found in the tenant named <MY_AAD_SUBSCRIPTION_ID>. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.
Is there something I can do in code or Azure Portal configuration to connect my 'tenant' to the ade.applicationinsights.io resource principal and get this connection working?
Adxproxy supports only tokens minted by Azure Active Directory (AAD). The token must be created for an Azure Data Explorer cluster (ADX), that you own. If you don't have your own ADX cluster, and for whatever reason you want to access your Application Insights resources via Adxproxy, you can always authenticate to 'https://help.kusto.windows.net' and use that token.

Unauthorized error while trying to create a new namespace in K8S

I am trying to create a namespace on a K8s cluster on Azure using teh fabric8 java client . Here is the code
#Before
public void setUpK8sClient() {
apiServer = "";
config = new ConfigBuilder().withMasterUrl(apiServer).withUsername("user").withPassword("pass").build();
client = new DefaultKubernetesClient(config);
System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true");
}
#Test
public void getClientVersion() {
System.out.println("Client version "+client.getApiVersion());
}
#Test
public void createNamespace() {
Namespace myns = client.namespaces().createNew()
.withNewMetadata()
.withName("myns")
.addToLabels("a", "label")
.endMetadata()
.done();
System.out.println("Namespace version " + myns.getStatus());
}
This gives me the following error
i
o.fabric8.kubernetes.client.KubernetesClientException: Failure executing: POST at: "https://...api/v1/namespaces. Message: Unauthorized! Token may have expired! Please log-in again. Unauthorized
What did I miss?
Since you are working on Azure, I guess you could follow the instructions to configure kubectl and then use the token from the kubeconfig file to access the cluster from the fabric8 client.
That token is probably an admin token, so you can also create new credentials (user/password) if you want to limit what the fabric8 client could do. API requests are tied to either a normal user or a service account, or are treated as anonymous requests.
Normal users are assumed to be managed by an outside, independent service (private keys, third parties like Google Accounts, even a file with a list of usernames and passwords). Kubernetes does not have objects which represent normal user accounts.
Service accounts are users managed by the Kubernetes API, bound to specific namespaces. Service accounts are tied to a set of credentials stored as Secrets. To manually create a service account, simply use the kubectl create serviceaccount ACCOUNT_NAME command. This creates a service account in the current namespace and an associated secret that holds the public CA of the API server and a signed JSON Web Token (JWT).

Invalid grant when accessing Google API

I'm trying to invoke any of the Google API using "Service account" authorization access. I have downloaded ".pk2" file and activated "URL Shortener API" in Services tab of Google API console. Whenever I try to invoke any API (URL shortener or Adsense). I've got following exception -
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "invalid_grant"
}
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:303)
at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:323)
at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:345)
at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:526)
at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:287)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:836)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:412)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:345)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:463)
Below is code snippet -
HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
JsonFactory JSON_FACTORY = new JacksonFactory();
File privateKey = new File(ReportAdsense.class.getResource("mykey.p12").toURI());
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("my_valid_account_id#developer.gserviceaccount.com")
.setServiceAccountScopes(UrlshortenerScopes.URLSHORTENER)
.setServiceAccountPrivateKeyFromP12File(privateKey)
.build();
Urlshortener service = new Urlshortener.Builder(new NetHttpTransport(), JSON_FACTORY, null).setHttpRequestInitializer(credential).build();
UrlHistory history = service.url().list().execute();
First of all "Service account" will not work for Adsense, since it requires user authorization. Hence for Adsense you should use Oauth 2.0. When you are authorized first time using URL https://accounts.google.com/o/oauth2/token, copy-paste and hardcode your refresh token. Than you can use it to get access token, specify client_id, client_secret and your refresh_token to get new access token. Now access token can be used in your application.
Regarding your error, I have faced with similar issue and spent plenty of time to resolve it. First of all, make sure that you are using valid ServiceAccountId - it should point to email which finishes with "developer.gserviceaccount.com". Make sure, that you specified account scopes and activated services in Google Console API.
I fixed this issue by synchronizing system clock in my machine.
There are a lot of topics with similar error without answers. Even more, some people says, that sometimes it works, sometimes it returns invalid grant. It could work on one machine and fail on another. I don't know if it is system clock issue, but I would avoid using Service Account API, since looks like there are bugs and support would not help you

Accessing Google Contacts Api via OAuth 2.0 and private key aka Service Account

I am currently implementing access to Google Contacts via OAuth 2.0 and a so called Service Account. The service account is generated for an ordinary user like "My.Name#gmail.com".
The code to generate the OAuth 2.0 credentials is:
public static GoogleCredential getCredentials() throws GeneralSecurityException, IOException {
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SingleUserCredentials.SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes("https://www.google.com/m8/feeds")
.setServiceAccountPrivateKeyFromP12File(new File(SingleUserCredentials.SERVICE_ACCOUNT_PKCS12_FILE_PATH))
.build();
credential.refreshToken();
return credential;
}
I am then trying to retrieve the contacts via:
ContactsService myService = new ContactsService(
"myApp");
myService.setOAuth2Credentials(getCredentials());
URL feedUrl = new URL("https://www.google.com/m8/feeds/contacts/default/full");
Query myQuery = new Query(feedUrl);
ContactFeed resultFeed = myService.query(myQuery, ContactFeed.class);
// Print the results
for (ContactEntry entry : resultFeed.getEntries()) {
System.out.println(entry.getName().getFullName().getValue());
System.out.println("Updated on: " + entry.getUpdated().toStringRfc822());
}
The problem is that I do not get any a single contact from my account. The feed is always empty. There is no error. Nothing.
When accessing a Google Apps managed domain via the same approach it works nicely.
I am wondering if the Contacts Api supports OAuth 2.0 for ordinary (aka #gmail.com) accounts when using a p12 key file and a service account.
I ran into that same problem myself.
I tried both the email address that I received when I setup the key and the email address of a domain administrator.
When I use the email from the key setup, I don't receive anything at all -- no warnings, no exceptions, and no data.
When I use the email address of a domain administrator, I receive an exception:
com.google.api.client.auth.oauth2.TokenResponseException: 400 OK
[java] {
[java] "error" : "invalid_grant"
[java] }
[java] Feb 5, 2013 5:16:48 PM com.google.appengine.repackaged.org.apache.http.impl.client.DefaultRequestDirector handleResponse
[java] WARNING: Authentication error: Unable to respond to any of these challenges: {}
[java] Feb 5, 2013 5:16:48 PM com.google.apphosting.utils.jetty.JettyLogger warn
[java] WARNING: /
[java] java.lang.NullPointerException: No authentication header information
...
So, I figured that the domain administrator's email address wasn't what I needed.
Next, I Googled around for a while before finding this page:
http://javadoc.google-api-java-client.googlecode.com/hg/1.13.2-beta/com/google/api/client/googleapis/auth/oauth2/GoogleCredential.html
I saw in there getServiceAccountUser (). The description of the field was:
Returns the email address of the user the application is trying to impersonate in the service account flow or null for none or if not using the service account flow.
Sure enough, there's a corresponding setServiceAccountUser (String) which accepts the username (email address) of the user you're using the service account to impersonate.
I set that field to an appropriate value and I was able to proceed.
In retrospect, it all makes sense -- if I don't supply an account that I'm trying to work from, I can't pull down the contacts for that account.
It is currently not possible to access Contacts using a service account as it is not supported in the Google APIs Console at Google APIs Console.
See also: Service Accounts
Second, it would only work with a Google managed domain because the Admin of the domain must grant access to the service account via the process below:
Delegate domain-wide authority to your service account
The service account that you created now needs to be granted access to the Google Apps domain’s user data that you want to access. The following tasks have to be performed by an administrator of the Google Apps domain:
Go to your Google Apps domain’s control panel. The URL should look like: "www.google.com/a/cpanel/mydomain.com"
Go to Advanced tools... > Manage third party OAuth Client access.
In the Client name field enter the service account's Client ID.
In the One or More API Scopes field enter the list of scopes that your application should be granted access to.
Click the Authorize button.
I've run across this very same error today but have given up on using Service Accounts for now, which I assume is not currently supported in the Contacts API. And so I am using Contacts API v3 with OAuth 1.0 and am getting the expected results.
ContactsService contactsService = new ContactsService(APPLICATION_NAME);
contactsService.setUserCredentials(CLIENT_USERNAME, CLIENT_SECRET);
URL contactFeedURL = new URL("https://www.google.com/m8/feeds/contacts/default/full");
Query contactFeedQuery = new Query(contactFeedURL);
ContactFeed contactFeed = contactsService.getFeed(contactFeedQuery, ContactFeed.class);

Resources