AWS for M&E Blog

Introducing Private Channels for Amazon Interactive Video Service

Today, Amazon Interactive Video Service (IVS) introduced Playback Authorization, a new feature which enables developers to launch private channels secured by JSON Web Tokens (JWTs). With just a little development, you can set up private channels that enable you to easily build subscription based live streaming services.

This is the first of a two-part blog series. In this post, we walk through how to:

  • Create a private channel and restrict channel access to subscribers using Amazon IVS.
  • Set up your first channel, and generate tokens to authorize playback.

Part two will share a sample application so you can examine a complete implementation and begin building the next great subscription video service.
Solution Overview

This workflow pipeline consists of an Amazon IVS channel, Elliptic Curve Digital Signiture Algorithm (ECDSA) key pair stored in AWS Secrets Manager, and an AWS Lambda function to vend authorization tokens. The Amazon IVS channel manages live play-out and timed metadata whereas the key pair is used by the Lambda function to generate tokens for viewer authorization.

Private channels in the Amazon IVS are protected via JSON Web Tokens (JWTs). Before you can generate JWTs, you must generate an ECDSA public/private key pair.

  • The private key is used to to sign a token to any of your streams that have enabled playback authentication.
  • The public key is used to upload to Amazon IVS and to verify the tokens signed with the private key.

While the overhead of authenticating users and securing the master playlist is managed by Amazon IVS service, the next step is to build a token vending service. This service is tasked with sending a user the JWT token to authenticate with.

The following walkthrough will guide you through generating a ECDSA key pair, as well as writing a serverless function in AWS Lambda to generate and vend a JWT token signed with your private key in order to authorize playback.

Implementation

Your first step is to enter the Amazon Interactive Video Service dashboard. You can find Amazon IVS by searching in the “Find Services“ bar under Media Services.

From the service dashboard, you will then need to create a new playback key. Go to the console. On the left navigation menu, select Playback keys. Then click Create playback key.

 

 

When prompted, type a Playback key name (a name for your playback ECDSA key pair).

 

 

Click Create to download a new private key. This can be used to sign tokens for any Amazon IVS private stream, so make sure you store it somewhere safe. Later in this tutorial, we will demonstrate how you can store a key in AWS Secrets Manager so that you can generate JWT tokens to send to clients. Now that your key is generated and stored on your local machine, you need to set up your first IVS channel.

This walkthrough will guide you through creating a brand new IVS channel. If you have already launched a channel and want to make use of it, you can still secure your channel by following in Enable Playback Authorization on Channels in the Amazon IVS User Guide.

To start creating a private channel, navigate to the Channels page and create a new channel. To create a private channel, you must choose Custom configuration and manually override some default options. After selecting Custom configuration, you should see a toggle to enable token authorization. Once everything is set up, your configuration should match the following screenshot. Once you verify the configuration, click the orange Create Channel button.

 

 

Now that the live channel is running, let’s create a simple API to return a JWT token for your channel and start authenticating users.

Before you writing any code, you first need to store the private key somewhere safe. For this example, you will store the private key in AWS Secrets Manager.

To upload your private key to Secrets Manager, you can use the AWS Command Line Interface (AWS CLI). Copy the following command and provide the location to your private key (aka pem key):

aws secretsmanager create-secret --name ivsprivatekey --cli-binary-format raw-in-base64-out --secret-binary file://private-key.pem
{
    "ARN": "arn:aws:secretsmanager:us-west-2:582048091268:secret:ivsprivatekey-uljBck",
    "Name": "ivsprivatekey",
    "VersionId": "ca768fe0-e690-466f-95df-6784676185e9"
}

Once the command completes you should see the success output in your terminal. In this response, you will notice a JSON object containing the Secret ARN, the name of the secret, and a version id GUID. Copy the ARN down from the CLI output as you will need it later to create an IAM policy with the proper permissions to access this private key.

Now that your private key is stored in Secrets Manager, you need to create a Lambda function and write the script to create your JWTs. This Lambda function serves as your authorizer and your signer for JWTs.

Open a new tab and navigate to the AWS Lambda service dashboard. Inside the Lambda console, select the Create Function button and create a new NodeJS 12.x function. Also, remember to create a new role with permissions to access Secrets Manager. This role should be similar to the following script. (Replace the <ARN_SECRET> with your Secrets Manager ARN from above)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-west-2:582048091268:log-group:/aws/lambda/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "secretsmanager:GetSecretValue"
            ],
            "Resource": [
                "<ARN_SECRET>"
            ],
            "Effect": "Allow"
        }
    ]
}

Now that you have proper permissions, you need to write the code for your Lambda function. Because this example uses additional NodeJS packages, you must do most of the work outside of the console.

Create a new folder locally to store your function. Paste the following commands to initialize a new Node project and install jsonwebtoken to help you sign your functions.

$ npm init
$ npm install jsonwebtoken

Next, create a new index.js file in the root of your folder to hold your Lambda function code. Take a minute to recall the Secret’s Manager ARN and Channel ARN you noted down earlier and paste the below script into index.js . Remember to replace the Secret ARN and Channel ARN with the ARNs specific to your deployment.

// Need to install this using npm install jsonwebtoken
var jwt = require('jsonwebtoken');
const aws = require('aws-sdk');
var globalPem;

exports.handler = async (event) => {
  if (globalPem === undefined) { 
      await getPemKey('<SECRET_ARN>');
  }
  var payload = {
    "aws:channel-arn": "<CHANNEL_ARN>",
    "aws:access-control-allow-origin": "*"
  };
  
  var token = jwt.sign(payload, globalPem, { algorithm: 'ES384', expiresIn: '2 days' });
  var tokenObj = {
    token
  };
  const response = {
    statusCode: 200,
    body: JSON.stringify(tokenObj),
    headers: {
      'Access-Control-Allow-Origin':'*',
    },
  };
  return response;
};

async function getPemKey(pemId) {
  const secretsManager = new aws.SecretsManager({ apiVersion: '2017-10-17' });
  const secret = await secretsManager.getSecretValue({ SecretId: pemId }).promise();
  globalPem = secret.SecretBinary;
}

Now you can simply point an API gateway to this Lambda function and it will return a signed token to the client. After the client receives the token, you can then configure your application to use that token as a parameter in the URL – for example, to start viewing the stream: https://<ivs_channel_url>?token=<token>

Congratulations! You have learned how to launch Amazon IVS private channels and create JWT tokens to allow your users to access the private channels. In the next edition of this blog post series, you will learn how to expand your existing token vending service while examining a real-world use case. It also describes how to implement a simple subscription-based service with user verification, multichannel support, and a modern front-end.