Skill 104 · AWS Media Services
Subchapter 104.23
references/workflow-live-event.mdMarkdown20 KBView on GitHub
Cross-service pattern guidance for live event workflows.
Signal chain: Source → MediaConnect → MediaLive → MediaPackage v2 → (MediaTailor) → CloudFront → Viewers
IF source is on-premises or remote (ST 2110, CDI, SRT):
→ Full chain: Source → MediaConnect → MediaLive → MediaPackage v2 → CloudFront
→ LOAD references/workflow-contribution-distribution.md for transport protocol details
IF source is cloud-native or direct push (RTMP, HLS pull):
→ Direct ingest: Source → MediaLive → MediaPackage v2 → CloudFront
IF delivering both H.264 and HEVC:
→ Dual channel: Source → MediaConnect → [ML Channel A (H.264) + ML Channel B (HEVC)] → MediaPackage v2 → CloudFront
IF user mentions redundancy, failover, multi-region, or epoch locking:
→ LOAD references/workflow-resilience-patterns.mdDEPENDENCY GRAPH:
Step 1 [VPC, IAM]
↓
Step 2 [MediaPackage v2] ──────────────────────────┐
↓ │
Step 3 [MediaConnect Flow] (if contribution) │
↓ │
Step 4 [MediaLive Input] │
↓ │
Step 5 [MediaConnect Output] (CDI only) │
↓ │
Step 6 [MediaLive Channel] ←── needs ingest URL ───┘
↓
Step 7 [MediaTailor] (optional)
↓
Step 8 [CloudFront]| Preconditions | None (first step) |
| Outputs | vpc_id, subnet_ids[] (≥2 AZs), security_group_id, iam_role_arn |
| Needed by | Steps 2-6 |
Actions:
The trust policy below is for the common case where MediaConnect feeds
MediaLive. If MediaConnect is NOT in the chain (e.g., RTMP_PUSH, SRT, or
HLS-pull direct to MediaLive), drop mediaconnect.amazonaws.com from the
Service array.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": ["medialive.amazonaws.com", "mediaconnect.amazonaws.com"]
},
"Action": ["sts:AssumeRole", "sts:TagSession"]
}]
}The role also needs permission policies sufficient for what each service
does — at minimum: mediapackagev2:PutObject on the target channel for
MediaLive→MediaPackage v2 ingest, plus any S3, SSM, secrets, or KMS
permissions the channel touches. Do NOT attach AmazonMediaLiveFullAccess
to a service role — that policy grants medialive:* and is intended for
human operators, not for the role MediaLive assumes.
MediaConnect input type: The role MUST include mediaconnect:ManagedDescribeFlow, ManagedAddOutput, and ManagedRemoveOutput with Resource flow:* + output:* (account/region scoped). Specific flow ARNs do not work.
Validation: Call iam:GetRole and confirm the principals match the
services in your chain. MediaConnect returns “Unable to assume role” if its
principal is missing when it is needed.
| Preconditions | IAM role exists (Step 1) |
| Outputs | channel_ingest_url, origin_endpoint_url |
| Needed by | Step 6 (ingest URL), Step 7/8 (origin endpoint URL) |
Actions:
InputType field — it is namespacing only)InputType: CMAF (or HLS)IF building the full chain with CloudFront (Step 8):
→ Do NOT add a policy here. Leave the endpoint in default-deny.
The OAC-scoped policy will be applied in Step 8 after the distribution
ID is known. An open (`Principal: "*"`) policy MUST NOT be used, even
temporarily.
IF dev/test only (no CDN, need immediate playback validation):
→ Add a scoped endpoint policy for `mediapackagev2:GetObject` with an
`aws:SourceIp` condition restricting to the developer's IP/CIDR, or
configure OAC from the start. Do NOT use `Principal: "*"`, even for
testing — an open policy is easily copied to production and left in place.Validation: GET {origin_endpoint_url} returns 200 (when authorized) or 403 (default-deny). If 403 from production traffic, the endpoint policy is missing or doesn’t match the CDN’s identity.
| Preconditions | VPC, subnets, security groups (Step 1) |
| Outputs | flow_arn, flow_source_ingest_ip |
| Needed by | Step 4 (MEDIACONNECT input type) or Step 5 (CDI output) |
| Skip if | Direct ingest (no contribution transport) |
IF source is ST 2110 JPEG XS or CDI:
→ Large (150 Mbps) or Extra Large (400 Mbps)
→ EFA interface REQUIRED
IF source is SRT/RTP ≤80 Mbps:
→ Standard (80 Mbps)
IF source is SRT/RTP >80 Mbps:
→ Large (150 Mbps)Actions:
Source-side ingest details (operationally required):
After the flow becomes ACTIVE, read the source-side ingest details from
the flow description and hand them to the team operating the source
encoder. For SRT listener and RTP/UDP sources, the relevant fields are
Flow.Source.IngestIp and Flow.Source.IngestPort — the encoder must
connect to that IP/port pair.
The source encoder is started later in the Startup Sequence (see below); without an active source feed, the channel will start but not produce output.
Validation: describe-flow shows Status: STANDBY and source configuration is correct. Once started, Status: ACTIVE and CloudWatch SourceBitRate > 0 confirms the encoder is actually delivering content.
| Preconditions | VPC, subnets (Step 1); MediaConnect flow (Step 3, if applicable) |
| Outputs | input_id, input_endpoint_ips[] |
| Needed by | Step 5 (CDI output destination), Step 6 (channel input attachment) |
IF MediaConnect is in chain AND source is NOT UHD:
→ MEDIACONNECT input type (references flow ARN directly)
→ This SKIPS Step 5 entirely (auto-wires output)
IF MediaConnect is in chain AND source IS UHD/uncompressed:
→ CDI input type
→ Step 5 is REQUIRED (manual output, same-AZ constraint)
IF no MediaConnect:
→ SRT, RTMP_PUSH, or RTP input type (direct from source encoder)Actions:
Pipeline redundancy (CRITICAL for STANDARD class):
A STANDARD-class MediaLive channel runs two pipelines and needs two
sources of content. The shape of the input depends on input type:
Validation: describe-input shows State: ATTACHED or DETACHED (not CREATING or DELETED). For MEDIACONNECT inputs on STANDARD channels, confirm MediaConnectFlows has two entries.
| Preconditions | Flow exists (Step 3), MediaLive input exists (Step 4) |
| Outputs | Output attached to flow |
| Needed by | Step 6 (content flows from source through to MediaLive) |
| Skip if | Using MEDIACONNECT input type (auto-wired) or no MediaConnect |
Constraint: MediaConnect output and MediaLive CDI input MUST be in the same AZ. Verify using AZ IDs (e.g., use1-az1), not AZ names.
Actions:
raw (video), pcm (audio), smpte291 (ancillary)Validation: describe-flow shows output with Status: ACTIVE after flow is started.
| Preconditions | Input (Step 4), MediaPackage ingest URL (Step 2), IAM role (Step 1) |
| Outputs | channel_id |
| Needed by | Startup sequence |
IF production live event:
→ STANDARD (dual-pipeline, automatic failover)
→ LOAD references/workflow-resilience-patterns.md for pipeline redundancy, input failover, and dual-AZ patterns
IF dev/test or cost-sensitive non-critical:
→ SINGLE_PIPELINEIF destination is MediaPackage v2:
→ CmafIngestGroupSettings (NOT HlsGroupSettings)
IF destination is S3 archive:
→ ArchiveGroupSettings
IF destination is non-MediaPackage HLS:
→ HlsGroupSettingsActions:
Destination wiring (CRITICAL for STANDARD class):
A MediaPackage v2 channel returns two ingest endpoints (IngestEndpoints[0]
and IngestEndpoints[1]) for pipeline redundancy. A STANDARD-class
MediaLive channel’s Destinations[].Settings array MUST contain BOTH
endpoint URLs — [0] for pipeline 0 and [1] for pipeline 1. Pumping
both pipelines into the same endpoint defeats the redundancy that STANDARD
class provides.
Destinations:
- Id: emp-dest
Settings:
- Url: <IngestEndpoints[0].Url> # pipeline 0
- Url: <IngestEndpoints[1].Url> # pipeline 1For SINGLE_PIPELINE channels, use one Settings entry with IngestEndpoints[0].Url.
IF using MediaTailor (ad insertion):
references/workflow-ad-insertion.md for SSAI scaling patterns and ADS configurationScte35Type: SCTE_35_WITHOUT_SEGMENTATION in CmafIngestGroupSettingsEXT-X-PROGRAM-DATE-TIME in output settingsCanonical CMAF Ingest output-group shape:
For MediaPackage v2, the typical pattern is one shared audio output plus one video-only output per ABR rung. This keeps a single audio rendition across all video qualities (no audio bitrate change on ABR switches) and matches what most production deployments do.
OutputGroups:
- Name: cmaf
OutputGroupSettings:
CmafIngestGroupSettings:
Destination: { DestinationRefId: emp-dest }
Scte35Type: SCTE_35_WITHOUT_SEGMENTATION # only when SCTE-35 is in use
Outputs:
# Shared audio output — referenced by all video rungs via the manifest
- OutputName: audio_aac
AudioDescriptionNames: [audio_shared]
OutputSettings:
CmafIngestOutputSettings: { NameModifier: _audio }
# Video-only outputs per rung
- OutputName: video_1080p
VideoDescriptionName: video_1080p
OutputSettings:
CmafIngestOutputSettings: { NameModifier: _1080p }
- OutputName: video_720p
VideoDescriptionName: video_720p
OutputSettings:
CmafIngestOutputSettings: { NameModifier: _720p }
- OutputName: video_480p
VideoDescriptionName: video_480p
OutputSettings:
CmafIngestOutputSettings: { NameModifier: _480p }AudioDescriptions[] defines audio_shared once. VideoDescriptions[]
defines video_1080p / video_720p / video_480p. Multiple language
tracks are added by defining additional AudioDescriptions and additional
audio-only Outputs (one per language).
Validation: describe-channel shows State: IDLE. Channel is ready to start.
| Preconditions | MediaPackage origin endpoint URL (Step 2), ADS URL from customer |
| Outputs | mediatailor_playback_url |
| Needed by | Step 8 (CloudFront origin) |
| Skip if | No ad insertion needed |
Actions:
Validation: GET {mediatailor_playback_url} returns a rewritten manifest with MediaTailor session tokens.
| Preconditions | MediaTailor URL (Step 7) or MediaPackage endpoint URL (Step 2) |
| Outputs | distribution_domain_name (viewer-facing URL) |
| Needed by | Viewers |
A CDN is REQUIRED for any production live workflow. MediaPackage v2 has a 1000 RPS hard limit and will not scale to viewer traffic without a CDN fronting it. Every CDN that pulls from MediaPackage v2 MUST have Origin Shield enabled.
Skip this step ONLY for dev/test workflows where viewer count is bounded and origin RPS is well below the limit.
IF using MediaTailor:
→ Origin = MediaTailor playback URL
→ MediaTailor session init (POST) requires AllowedMethods to include POST
IF no MediaTailor:
→ Origin = MediaPackage v2 origin endpoint URL
→ Configure OAC (Origin Access Control), and set the MediaPackage v2
endpoint policy to allow only this distributionActions:
Create custom cache policies (MUST be created before the distribution):
CachingOptimized MUST NOT be used for manifest behaviors. It sets a 24-hour default TTL that causes stale manifests.Set ViewerProtocolPolicy: redirect-to-https on all cache behaviors to enforce encryption in transit. If using a custom domain (CNAME), attach an ACM certificate provisioned in us-east-1 and set minimum protocol version to TLSv1.2_2021.
Create OAC (Origin Access Control):
mediapackagev2Create the CloudFront distribution with MediaPackage v2 origin, attach the OAC from step 3. Capture the distribution ID from the response.
MUST update the MediaPackage v2 endpoint policy to allow ONLY this distribution. This step is REQUIRED — without it, CloudFront receives 403 from the endpoint. The policy requires the distribution ARN from step 4:
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowCloudFrontOAC",
"Effect": "Allow",
"Principal": {"Service": "cloudfront.amazonaws.com"},
"Action": "mediapackagev2:GetObject",
"Resource": "<origin-endpoint-ARN>",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::<account>:distribution/<distribution-ID>",
"aws:SourceAccount": "<account>"
}
}
}]
}This replaces any prior testing policy (e.g., an aws:SourceIp-scoped dev policy). If the endpoint had no policy before this step, CloudFront will return 403 until this policy is applied — that is expected and correct. Do NOT fall back to a permissive policy to avoid the transient 403.
If MediaTailor SSAI is used (Step 7), additionally allow mediatailor.amazonaws.com with action mediapackagev2:GetObject in the same endpoint policy. MediaTailor fetches origin manifests directly from MediaPackage, not through CloudFront. Scope this service-principal grant against cross-service confused-deputy abuse: agents MUST add an aws:SourceAccount (your account id) condition and SHOULD add aws:SourceArn (the playback-configuration ARN), so only your own MediaTailor configurations can exercise it.
Configure cache behaviors using the cache policy IDs from step 1:
Set error caching TTL = 1 second for all error codes (403, 404, 500, 502, 503, 504)
Enable Origin Shield (region closest to origin)
Forward all query strings and User-Agent header (required for MediaTailor ADS targeting)
Constraint: OAC MUST be configured when CloudFront fronts MediaPackage v2. Without it, the origin endpoint remains publicly accessible, exposing it to DDoS and bypassing the CDN’s 1000 RPS protection. Agents MUST NOT leave endpoints with Principal: "*" after adding CloudFront.
Constraint: Cache policies are a prerequisite dependency. The create-cache-policy calls MUST complete and return policy IDs BEFORE calling create-distribution. Do NOT substitute managed policies to avoid this step.
Validation: GET https://{distribution_domain_name}/{manifest_path} returns #EXTM3U with expected variant streams.
Logging: Enable CloudFront standard logging (v2) to S3 for operational visibility. For high-concurrency live events, enable real-time logs to Kinesis Data Streams for seconds-latency debugging of cache behavior and viewer errors.
Start upstream first. Poll each resource to its running state before proceeding.
| Order | Action | Poll | Ready state | Notes |
|---|---|---|---|---|
| 1 | start-flow (MediaConnect) | Flow.Status | ACTIVE | Billing starts here |
| 1b | (Router input only) Confirm router I/Os are Active and a route is assigned to the MediaLive-facing output | I/O state / route | Active + route assigned | Content flows only once a route is “taken” to the output |
| 2 | Start source encoder | CloudWatch SourceBitRate > 0 | — | Confirm content flowing |
| 3 | start-channel (MediaLive) | State | RUNNING | Async — poll until RUNNING; large channels take longer |
| 4 | Verify end-to-end | GET manifest URL | #EXTM3U with variants | Check IngressBytes > 0 |
MediaConnect Router startup: When using a MediaConnect Router (MediaConnect router input type), start the router I/Os (Standby→Active) and the MediaLive channel. Content reaches the MediaLive input only once the router I/Os are Active AND a route has been assigned (“taken”) to the output feeding that input — there is no separate “enable output” API. Per the AWS setup order, routes may be assigned before or after starting the I/Os.
Reverse of startup. Poll each resource to its stopped state before proceeding.
| Order | Action | Poll | Stopped state | Notes |
|---|---|---|---|---|
| 1 | stop-channel (MediaLive) | State | IDLE | — |
| 2 | Stop source encoder | — | — | — |
| 3 | stop-flow (MediaConnect) | Flow.Status | STANDBY | Billing stops here |
Lifecycle reminder: A flow left in ACTIVE and a channel left in
RUNNING continue to bill until explicitly stopped. After any non-permanent
event (test runs, recurring linear windows that have a defined off-period,
post-event teardown), confirm both resources are in their stopped state.
For long-lived 24/7 channels, this guidance applies only to the test/staging
copies — production-linear channels are expected to stay running.