Back to Opa

Deploying OPA on AWS ECS

docs/docs/deploy/aws/ecs.mdx

1.16.29.6 KB
Original Source
<!-- Manual Heading imports are needed because the ParamProvider plugin provider hides anchors from the broken link checker -->

import Heading from '@theme/Heading';

Amazon ECS (Elastic Container Service) is a managed platform for running containerized applications. Software already packaged as containers, like OPA, is easy to run on ECS. ECS takes care of scaling, networking, and infrastructure, allowing you to focus on building and integrating your applications.

ECS is great for hosting a centralized OPA, Policy Decision Point (PDP) service to be accessed by Policy Enforcement Points (PEPs, e.g. business apps and services) running elsewhere in your environment. ECS also supports running OPA as a daemon or additional container alongside your other application containers too but this pattern is not covered here.

This guide will explain the steps and key considerations for deploying an OPA service using ECS.

Supplying Configuration to OPA

While the default OPA configuration is simple, OPA has many different options and settings. Like many other tools, OPA is commonly configured using a file mounted into its container at a known path. There are many ways to configure OPA on ECS:

Since the preferred option is largely dependent on your organization's approach to secrets management, we leave this exercise to the reader. The following guide uses command line configuration with secrets loaded from KMS, to keep the example simple to follow.

Selecting or Creating an ECS Cluster

An ECS cluster is a logical grouping of Amazon Elastic Container Service (ECS) resources used to run and manage Docker containers using AWS Fargate.

All applications running in ECS are part of an ECS cluster. When creating a cluster for OPA, it's recommended to use the Fargate infrastructure type - rather than EC2. Please see our EC2 Guide if you'd like to run OPA on EC2.

Within our cluster, we will be running OPA using the following architecture:

mermaid
graph
  subgraph AWS
  subgraph KMS
    Secret
  end
  subgraph ECS Cluster
    subgraph Service
      subgraph Task
        opa["OPA Container"] <--> Secret
      end
    end
  end
  end
<!-- markdownlint-disable MD044 --> <!-- markdownlint-disable MD034 -->

<ParamProvider initialParams={{ service: 'my-opa', region: 'us-east-1', secretARN: 'arn:aws:secretsmanager...', taskRoleArn: 'arn:aws:iam:...', version: '...', }}

<Heading as="h2" id="creating-a-secret-and-iam-role-for-your-opa-task">Creating a Secret and IAM Role for your OPA Task</Heading>

OPA needs to download policy at startup. Often credentials are needed to download new policy and data bundles. These might be an API token, or username/password combination depending on how your bundles are hosted. These credentials must be securely stored. In this section, we’ll create a secret in AWS Secrets Manager, an IAM policy to access the secret, and an IAM role with that policy for the ECS task to use.

:::tip Unsure how to authenticate OPA such that it can download bundles? Have a look at the configuration documentation.

In this example we set an example TOKEN from the secret as an example using CLI flags. :::

Create a secret with any variables you need such as TOKEN etc. Once you have created the secret, note it's ARN here set it in the later steps: <InlineEditable paramKey="secretARN"/>. Create a IAM policy with the following rules to allow the OPA task to access the secret:

<ParamCodeBlock> {` { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "secretsmanager:GetSecretValue", "Resource": "{{secretARN}} } ] } `} </ParamCodeBlock>

Now you can create a new Role referencing this policy to use as the taskRoleArn for the rest of the guide. When you have created the role, note the task's ARN here to populate the later steps: <InlineEditable paramKey="taskRoleArn"/>.

<Heading as="h2" id="creating-an-opa-task-definition">Creating an OPA Task Definition</Heading>

An ECS task definition is a blueprint that describes how containers should run in AWS ECS, specifying details like container images, commands and resource requirements. In this section, we will build a task definition for use on ECS to run OPA.

Before continuing, please ensure you have set the following:

  • Service Name: <InlineEditable paramKey="service"/> (This is the name for the service as it will appear in ECS)
  • Secret ARN: <InlineEditable paramKey="secretARN"/> (if configuration depends on secret values for some variables)
  • Region: <InlineEditable paramKey="region"/>
  • OPA Version: <InlineEditable paramKey="version"/>, e.g. X.Y.Z not latest or vX.Y.Z. Review the OPA images for a list of available versions.
<!-- markdownlint-disable MD044 --> <!-- markdownlint-disable MD034 --> <ParamCodeBlock> {` { "family": "{{service}}", "containerDefinitions": [ { "name": "opa", "image": "openpolicyagent/opa:{{version}}", "cpu": 0, "portMappings": [ { "name": "opa-8181-tcp", "containerPort": 8181, "hostPort": 8181, "protocol": "tcp" } ], "essential": true, "command": [ "--server", "--set", "\"default_decision=/http/example/authz/allow\"", "--set", "\"services.example_com.url=https://example.com/control-plane-api/v1\"", "--set", "\"services.example_com.credentials.bearer.token=\${TOKEN}\"", ], "healthCheck": { "command": [ "CMD", "/opa", "eval", "-f", "pretty", "--fail", "200 = http.send({\"url\": \"http://localhost:8181/health\", \"method\": \"get\"}).status_code" ], "interval": 30, "timeout": 5, "retries": 2, "startPeriod": 10 }, "environment": [], "mountPoints": [], "volumesFrom": [], "secrets": [ { "name": "TOKEN", "valueFrom": "{{secretARN}}:TOKEN::" }, ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/{{service}}", "mode": "non-blocking", "awslogs-create-group": "true", "max-buffer-size": "25m", "awslogs-region": "{{region}}", "awslogs-stream-prefix": "ecs" } }, "systemControls": [] } ], "taskRoleArn": "{{taskRoleArn}}", "networkMode": "awsvpc", "volumes": [], "placementConstraints": [], "requiresCompatibilities": [ "FARGATE" ], "cpu": "1024", "memory": "2048", "runtimePlatform": { "cpuArchitecture": "X86_64", "operatingSystemFamily": "LINUX" } } `} </ParamCodeBlock>

:::warning If you have configured OPA to use another port than 8181, make sure to update the health localhost port too. :::

<Heading as="h2" id="deploying-opa-on-the-cluster">Deploying OPA on the Cluster</Heading>

Once you have a task definition in place, you can deploy it to your ECS cluster.

  1. Create a new service in the cluster where you'd like to deploy OPA.
  2. Use a Service as the Application type, OPA will be a long running service.
  3. Select <InlineEditable paramKey="service"/> as the Family of task definitions.

Once the service is created, ECS will start a task using the task definition and you should see the OPA is accessible shortly after.

</ParamProvider>

Accessing the OPA service

There are many options to access the OPA service running on ECS from your PEPs. The right option for your use case will depend on the location of OPA's callers in your infrastructure - among other factors like security and performance. A brief overview of some options is provided below.

  • Application Load Balancer (ALB): Well suited to OPA's REST API HTTP traffic, ALB operates at Layer 7 and supports advanced routing features. Use an ALB when you need to route requests to OPA based on URL paths or host headers or require integration with AWS services like AWS WAF.
  • Network Load Balancer (NLB): Best suited for high performance OPA use cases where response times are critical. Read more about NLB integration with ECS.
  • Service Discovery with AWS Cloud Map: Allows internal clients within the same VPC to access the OPA service using DNS names. Opt for this when your OPA clients are inside your AWS network, and you want to avoid exposing services to the internet.