I encoded a bunch of videos in Azure Media Services and created streaming endpoints. Everything works as expected. Now, I'd like to protect the endpoint URL for each video. For example, I'd like to make each URL available conditionally (for example up to an hour per user). Is it possible to define SAS tokens (similar to Azure Storage SAS tokens) for streaming endpoints? Or something similar that could do the job?
You can read offical doc first.
Tutorial: Use DRM dynamic encryption and license delivery service
After consulting the information, there should be no similar use of SAS to protect media resources. Generally, SAS is used to access resources in Storage.
In this tutorial, we specify for the content key policy to have a token restriction. The token-restricted policy must be accompanied by a token issued by a security token service (STS). Media Services supports tokens in the JWT formats and that's what we configure in the sample.
JwtSecurityToken token = new JwtSecurityToken(
issuer: issuer,
audience: audience,
claims: claims,
notBefore: DateTime.Now.AddMinutes(-5),
expires: DateTime.Now.AddMinutes(60),
signingCredentials: cred);
I think expires can meet your needs.
Build a streaming URL
// Look for just the DASH path and generate a URL for the Azure Media Player to playback the encrypted DASH content.
// Note that the JWT token is set to expire in 1 hour.
if (path.StreamingProtocol == StreamingPolicyStreamingProtocol.Dash)
{
uriBuilder.Path = path.Paths[0];
dashPath = uriBuilder.ToString();
}
Related
I have troubles acquiring an azure video indexer (ARM based) token as a deamon app.
(I am able to upload a video using the portal generated token ). So I started by creating a registered App with with a client_secret I will use to request a token on the video indexer /generateAccessToken enpoint.
This registered app has the scope 'https://management.azure.com/user_impersonation' image description and added the registered app as Contributor on the video indexer RBAC (don't think it's necessary, but I did it to be sure)
When I get the token from '*https://login.microsoftonline.com/fbe3354f-$$$$-404a-8d93-da9b01b57c28/oauth2/v2.0/token*' an use it to request a video indexer token on '*https://management.azure.com/subscriptions/665eef5b-$$$$-43ad-9ec5-4afc5cd0a0e5/resourceGroups/ween-global/providers/Microsoft.VideoIndexer/accounts/ween-video-indexer/generateAccessToken?api-version=2022-04-13-preview*' I get this response :
{
"error": {
"code": "ResourcePostActionFailed",
"message": "ResourcePostActionFailed: Access Denied"
}
Does any one have an idea on how to proceed ?! Don't even know if what I did do far is right or not... : (
What Id did step by step
First round :
Created an ARM Video Indexer account through the portal,
I created a User managed identity for the Video Indexer to connect to Media Services (system managed identities were having issues)
Added this managed identity as a contributor for Media services.
Generated a "Contributor/Account" Video Indexer token using the portal
I uploaded a video using this token. Round successful ! 👍
Round 2 :
I need now a way to generate this "portal generated" video indexer token, because it lasts for 1h. In order to do that as a deamon app :
I created a App registration on the active directory,
I Set up a client secret for this app,
I added an Api persmision 'https://management.azure.com/user_impersonation' image description
I added this Registered App as a contributor on the video indexer resource,
I can now retrieve an Azure basic credential token with the scope 'https://management.azure.com/.default' for this app on this endpoint : https://login.microsoftonline.com/fbe3354f-$$$$-404a-8d93-da9b01b57c28/oauth2/v2.0/token
When I try to use this credential to generage a "Contributor/Account" video indexer token on the endpoint : https://management.azure.com/subscriptions/665eef5b-$$$$-43ad-9ec5-4afc5cd0a0e5/resourceGroups/ween-global/providers/Microsoft.VideoIndexer/accounts/ween-video-indexer/generateAccessToken?api-version=2022-04-13-preview I got the following error
{
"error": {
"code": "ResourcePostActionFailed",
"message": "ResourcePostActionFailed: Access Denied"
}
}
It's like the Registered app is not allowed to access the video indexer api. Don't know why, because what I understood is that the access to the video indexer is now managed by RBAC policies and I added the registered app as a contributor of the video indexer resource. I must have done something wrong, or missed somehting important... 😟
✔️ Resolution
I was sending an additionnal header 'Ocp-Apim-Subscription-Key' that was not expected and this was causing the this error response. Removing this additional header permit me to retrieve the video indexer token ! : )
After 2 days of suffering and long tailed email exchange with Microsoft support I got the sequence which will work. At least to this current date 7 July 2022.
You'd have to do a generic HTTP call to fetch an access token. You can test this call in the browser via this link: https://learn.microsoft.com/en-gb/rest/api/videoindexer/generate/access-token#code-try-0, but it uses your login and password in order to pass Authentication bearer in the header
So, if you are doing it in logic app or a function you need to have an identity to pass which is AD OAuth token
You can either generate it for system-assigned managed identity or in which case it would your own App registrations identity, below you can see an example of form details who they are in Logic apps https://i.stack.imgur.com/EyUqJ.png
If you decide to go with your own App registrations identity you would need to give it Contributor permissions on Video Indexer and associated Media Service, but mainly you'd have to create and assign a custom role that will have
Microsoft.VideoIndexer/accounts/generateAccessToken/action permission
Once you have the access token you then can upload and index a video file without any issues.
I am trying to upload a video file and stream it with DRM using Azure Media Services,
So far I managed to upload the file, get a streaming URL and get a token but when trying to play it on http://ampdemo.azureedge.net/ I am getting an error
Unable to decrypt encrypted video source 0x20500004
Been searching for a couple of hours now for what might cause the issue but haven't found anything that helped.
I used this repo (and changed the keys to my own)
https://github.com/Azure-Samples/media-services-v3-node-tutorials/blob/main/StreamFilesWithDRMSample/index.ts
In addition, I created a content key policy named CommonEncryptionCencDrmContentKeyPolicy with license type PlayReady and Restriction type token
Can anyone help and share what am I missing here?
Thanks!
Make sure you are using https:// for everything.... don't mix http: on any URLs
That's usually the issue.
Update:
I can't quite spot the issue within the token, but it could be something to do with the way that you have defined the restriction in the ContentKeyPolicyTokenRestriction object.
Make sure that your issuer and audience match what you passed into the JWT token. If the sample worked for you, it might be the difference.
let restriction: ContentKeyPolicyTokenRestriction = {
odataType: "#Microsoft.Media.ContentKeyPolicyTokenRestriction",
issuer: issuer,
audience: audience,
primaryVerificationKey: primaryKey,
restrictionTokenType: "Jwt",
alternateVerificationKeys: undefined,
requiredClaims: requiredClaims
}
Check through all pats that set the Content Key Policy token restriction up, and make sure that it matches your required claims passed into the JWT token.
I use azure-sdk-for-js (NodeJS).
Particularly - #azure/storage-blob#12.6.0.
I have a service which generates SAS tokens and they expire in few minutes. I want somehow request new tokens after previous expire. And this should be done even in the middle of operation. Because when I upload big file to blob, in the middle SAS token expires and upload fails.
I have a worked example of what I need, but with EventHub.
I create event hub client with:
new EventHubProducerClient(eventHubHost, eventHubName, sasGenerator)
And sasGenerator is emplementation of TokenCredential. It returns generated AccessToken (which have SAS token and expiresOnTimestamp). And if I got it correctly, EventHubProducerClient use my sasGenerator to refresh tokens when needed.
I found that BlobServiceClient have similar argument credential which can have type of TokenCredential. But the same approach as with EventHub doesn't work:
new BlobServiceClient(blobHost, sasGenerator)
Example of Error:
RestError: Server failed to authenticate the request. Please refer to the information in the www-authenticate header
I also was able to use generated SAS token with AnonymousCredential and it works. But I'm not able to upload big file to blob because the token expires earlier.
Please check the below points ,if they can be worked around
The error Server failed to authenticate the request. Please refer to the information in the www-authenticate header possibly may be due to an issue with your account name/key stored in the the config file or connection string.
It may be due to permissions not in correct order .See Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. And valid permission order.
Came across this Article on how to inject new SAS for an ongoing uploading .
The scenario provides sample to request a new SAS token during the uploading instead of starting a new upload.
SEE:
work-with-shared-access-signatures
Best practices using sas
We need to set up continuous data export from Kusto to an external table for data older than 60 days into ADLS. Based on documentation it looks like we should use AAD token to Productionize, however, the documentation does not clearly specify the process to generate AAD token.
We also followed the Microsoft Documentation to acquire the access token and registered an application, generated client secret key.
Need some help/suggestion regarding the process to generate the token
Append ;token=AadToken to the URI, with AadToken being a base-64 encoded AAD access token (make sure the token is for the resource https://storage.azure.com/).
.create external table logs (ing_dt:date,record:string)
kind=adl
partition by bin(ing_dt, 1d)
dataformat=json
(
h#'abfss://filesystem#<storageaccountname>.dfs.core.windows.net/input;token=*****)
with
(
docstring = "External Table",
folder = "External",
nameprefix= "ext"
)
.create-or-alter continuous-export exp_logs
to table logs
with
(intervalBetweenRuns=1h)
<| source
| extend ing_dt=format_datetime(ingestion_time(),'yyyy-MM-dd')
| project todatetime(ing_dt), record
| where todatetime(ing_dt) < ago(60d)
The documentation you linked to references AAD client libraries to generate access token (see this section). For example, AcquireToken method if you're using .NET. However, AAD access tokens have a very short expiry (can be extended up to 1 day, I think) so it's not recommended to use those for continuous export, as ADX cannot renew the token and the export will start failing once the token has expired. The recommended authentication method for continuous export is either using an account key, or a SAS key (with a very long expiry). Both are documented here.
We make use of a thrird party Email Service Provider (ESP) to send emails to our customers. One of the emails needs to have a file attached to it. To accomplish this we need to give the ESP a URL of the file. The ESP will download the file and attach it to the email.
We are now working on a solution to secure the URL to limit the risk of unauthorized downloads. The ESP cannot authenticate itself while making the request to the URL, so the only option we see is by making the URL hard to guess and making it valid for a limited time.
The way we want to accomplish this is by putting a token in the URL's querystring. The service that hosts the file will validate the token and authorize access. The token will need to expire in time and should only give access to a specific file.
We already have a IdentityServer 3 implementation running an oAuth2 Security Token Service. Our plan is to let this service generate the tokens that will be put in the query string of the file download URL. We are considering creating a custom oAuth2 grant type to support tokens that will only allow access to a specific resource.
This would be an example of a request to the oauth2 token endpoint with the custom grant:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=custom_grant&scope=attachment.read&resource_id=xxxxx
The STS will return a token with a claim of the resource ID the token will give access to.
Is the right use case for a custom grant type or should we look for a different way to implement this?
I think what you're proposing is fine, but I personally prefer using something based on cryptographic signatures for this sort of thing.
JSON Web Token is a well-established way to do this with support in a lot of programming languages. Essentially, you sign a JSON dictionary, including an expiration time. Then you attach it to the URL (e.g. as a query parameter). When receiving an inbound request, you validate the token by checking the signature, expiration time, and the resource it says it applies to.
The advantage of this approach is that there's no needless state: you don't have to store tokens anywhere and instead just need a signing key.
Here's an example in Python that shows the basic idea:
import time
import jwt
SIGNING_SECRET = 'use-a-good-secret-here'
token = jwt.encode({
'resource_id': 'xxxxx',
# JSON spec establishes "exp" as meaning expiration time
'exp': time.time() + 1, # one second in the future for testing
}, SIGNING_SECRET, algorithm='HS256')
print(token)
def try_decoding(token):
try:
decoded = jwt.decode(token, SIGNING_SECRET, algorithms=['HS256'])
print('Valid token for "{}"'.format(decoded['resource_id']))
except jwt.exceptions.ExpiredSignatureError:
print('The token has expired.')
try_decoding(token) # prints 'Valid token for "xxxxx"'
print('Sleeping until the token expires...')
time.sleep(2)
try_decoding(token) # prints "The token has expired."