mirror of
https://github.com/kemko/nomad.git
synced 2026-01-05 09:55:44 +03:00
* seo operation section * other specifications section * Update website/content/docs/other-specifications/variables.mdx Co-authored-by: Jeff Boruszak <104028618+boruszak@users.noreply.github.com> --------- Co-authored-by: Jeff Boruszak <104028618+boruszak@users.noreply.github.com>
407 lines
14 KiB
Plaintext
407 lines
14 KiB
Plaintext
---
|
|
layout: docs
|
|
page_title: Federate access to AWS with Nomad Workload Identity
|
|
description: |-
|
|
Integrate Nomad as an OpenID Connect (OIDC) provider with AWS IAM identity and use workload identity to federate access to AWS resources and services.
|
|
---
|
|
|
|
# Federate access to AWS with Nomad Workload Identity
|
|
|
|
This page describes how to integrate Nomad with AWS IAM as an OpenID Connect (OIDC) provider and
|
|
use [Workload Identity] to federate access to AWS resources and services. In this workflow, Nomad
|
|
is the [OpenID Connect Provider] (OP or OIDC provider) and generates JSON Web Tokens (JWTs) which
|
|
serve as workload identities. AWS IAM is the Relying Party (RP) and validates these workload
|
|
identity tokens with Nomad before it permits federated access to resources and services.
|
|
|
|
## Prerequisites
|
|
|
|
To integrate Nomad and AWS IAM identity, you need a running Nomad cluster that
|
|
meets the following prerequisites:
|
|
|
|
- Nomad v1.7.x or later
|
|
- TLS enabled
|
|
|
|
The instructions on this page also assume the following:
|
|
|
|
- Your AWS account has the necessary permissions to create IAM roles, policies, hosted zones,
|
|
and certificates.
|
|
- You are using Terraform to manage your AWS infrastructure and you have
|
|
[configured it to communicate with AWS](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration).
|
|
|
|
## Workflow
|
|
|
|
The process to integrate Nomad as an OIDC provider with AWS consists of the following steps:
|
|
|
|
1. Create the required AWS resources:
|
|
- [Route 53 hosted zone](#create-a-hosted-zone)
|
|
- [AWS Certificate Manager SSL certificates](#generate-ssl-certificates)
|
|
- [Load balancer and listener](#create-an-application-load-balancer)
|
|
- [DNS Alias for the load balancer](#create-a-dns-alias)
|
|
- [OIDC Identity Provider](#create-an-oidc-identity-provider)
|
|
- [AWS IAM role](#create-an-iam-policy-for-oidc-federated-users)
|
|
1. Update the Nomad server configuration.
|
|
1. Create a jobspec file that accesses AWS and then run it to verify your configuration.
|
|
|
|
## Create and configure AWS resources
|
|
|
|
To use Nomad as an identity provider, you need to have a trusted SSL certificate for the
|
|
domain used by the cluster. The following example uses AWS Certificate Manager (ACM).
|
|
|
|
### Create a hosted zone
|
|
|
|
Use the [`aws_route53_zone` resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone).
|
|
|
|
```hcl
|
|
variable "domain_name" {
|
|
type = string
|
|
default = "<DOMAIN_NAME>"
|
|
}
|
|
|
|
resource "aws_route53_zone" "example" {
|
|
name = var.domain_name
|
|
}
|
|
```
|
|
|
|
This configuration requires the following information:
|
|
- [`<DOMAIN_NAME>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone#name):
|
|
The domain name of your Nomad cluster without the protocol or port. `var.domain_name` is used
|
|
throughout the examples on this page to reference `<DOMAIN_NAME>`.
|
|
|
|
### Generate SSL certificates
|
|
|
|
Use the [`aws_acm_certificate`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate)
|
|
and [`aws_acm_certificate_validation`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) resources to create a request and provide validation for an SSL
|
|
certficiate.
|
|
|
|
```hcl
|
|
variable "zone_id" {
|
|
type = string
|
|
default = "<HOSTED_ZONE_ID>"
|
|
}
|
|
|
|
resource "aws_acm_certificate" "example" {
|
|
domain_name = var.domain_name
|
|
validation_method = "DNS"
|
|
|
|
lifecycle {
|
|
create_before_destroy = true
|
|
}
|
|
}
|
|
|
|
resource "aws_route53_record" "cert_dns" {
|
|
allow_overwrite = true
|
|
name = tolist(aws_acm_certificate.example.domain_validation_options)[0].resource_record_name
|
|
records = [tolist(aws_acm_certificate.example.domain_validation_options)[0].resource_record_value]
|
|
type = tolist(aws_acm_certificate.example.domain_validation_options)[0].resource_record_type
|
|
zone_id = var.zone_id
|
|
ttl = 60
|
|
}
|
|
|
|
resource "aws_acm_certificate_validation" "example" {
|
|
certificate_arn = aws_acm_certificate.example.arn
|
|
validation_record_fqdns = [aws_route53_record.cert_dns.fqdn]
|
|
}
|
|
```
|
|
|
|
This configuration requires the following information:
|
|
- [`<HOSTED_ZONE_ID>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record#zone_id):
|
|
The ID of the hosted zone. This will be `aws_route53_zone.example.zone_id` if you are using the
|
|
examples from this page.
|
|
|
|
### Create an Application Load Balancer
|
|
|
|
Use the [`aws_lb` resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb).
|
|
|
|
```hcl
|
|
resource "aws_lb" "test" {
|
|
name = "test-lb-tf"
|
|
internal = false
|
|
load_balancer_type = "application"
|
|
security_groups = [<SECURITY_GROUP_ID>]
|
|
subnets = [<SUBNET_IDS>]
|
|
|
|
enable_deletion_protection = true
|
|
|
|
access_logs {
|
|
bucket = <S3_BUCKET_ID>
|
|
prefix = "test-lb"
|
|
enabled = true
|
|
}
|
|
}
|
|
```
|
|
|
|
This configuration requires the following information:
|
|
- [`<SECURITY_GROUP_ID>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb#security_groups):
|
|
A list of security groups IDs that you want to apply to the load balancer.
|
|
- [`<SUBNET_IDS>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb#subnets):
|
|
A list of subnet IDs that you want to attach to the load balancer.
|
|
- [`<S3_BUCKET_ID>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb#bucket):
|
|
The ID of an S3 bucket to store the load balancer access logs in.
|
|
|
|
### Create a load balancer listener
|
|
|
|
Use the [`aws_lb_listener` resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener).
|
|
|
|
```hcl
|
|
resource "aws_lb_listener" "example" {
|
|
load_balancer_arn = <LB_ARN>
|
|
port = "443"
|
|
protocol = "HTTPS"
|
|
ssl_policy = "ELBSecurityPolicy-2016-08"
|
|
certificate_arn = <CERT_ARN>
|
|
|
|
default_action {
|
|
type = "forward"
|
|
target_group_arn = <LB_TARGET_GROUP_ARN>
|
|
}
|
|
}
|
|
```
|
|
|
|
This configuration requires the following information:
|
|
- [`<LB_ARN>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener#load_balancer_arn):
|
|
The AWS resource name of the load balancer. This will be `aws_lb.test.arn` if you are using the
|
|
examples from this page.
|
|
- [`<CERT_ARN>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener#certificate_arn):
|
|
The AWS resource name of the load balancer's certificate. This will be
|
|
`aws_acm_certificate_validation.example.certificate_arn` if you are using the examples from this
|
|
page.
|
|
- [`<LB_TARGET_GROUP_ARN>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener#target_group_arn): The AWS resource name of the target group for the load balancer to route traffic to. This group
|
|
includes your Nomad server instances.
|
|
|
|
### Create a DNS Alias
|
|
|
|
Use the [`aws_route53_record` resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record).
|
|
|
|
```hcl
|
|
resource "aws_route53_record" "www" {
|
|
zone_id = <HOSTED_ZONE_ID>
|
|
name = var.domain_name
|
|
type = "A"
|
|
|
|
alias {
|
|
name = <LB_ALIAS_DNS_NAME>
|
|
zone_id = <LB_ALIAS_ZONE_ID>
|
|
evaluate_target_health = true
|
|
}
|
|
}
|
|
```
|
|
|
|
This configuration requires the following information:
|
|
- [`<HOSTED_ZONE_ID>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record#zone_id):
|
|
The ID of the hosted zone. This will be `aws_route53_zone.example.zone_id` if you are using the
|
|
examples from this page.
|
|
- [`<LB_ALIAS_DNS_NAME>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record#name):
|
|
The DNS
|
|
name of the load balancer. This will be `aws_lb.test.dns_name` if you are using the examples
|
|
from this page.
|
|
- [`<LB_ALIAS_ZONE_ID>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record#zone_id):
|
|
The zone ID of the load balancer. This will be `aws_lb.test.zone_id` if you are using the
|
|
examples from this page.
|
|
|
|
### Create an OIDC Identity Provider
|
|
|
|
Use the [`aws_iam_openid_connect_provider` resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_openid_connect_provider).
|
|
|
|
```hcl
|
|
data "tls_certificate" "example" {
|
|
url = <CERT_DOMAIN_NAME>
|
|
}
|
|
|
|
resource "aws_iam_openid_connect_provider" "nomad" {
|
|
# Nomad HTTPS URL
|
|
url = <CERT_DOMAIN_NAME>
|
|
|
|
client_id_list = [
|
|
"aws",
|
|
]
|
|
|
|
thumbprint_list = [data.tls_certificate.example.certificates.0.sha1_fingerprint]
|
|
}
|
|
```
|
|
|
|
This configuration requires the following information:
|
|
- [`<CERT_DOMAIN_NAME>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_openid_connect_provider#url):
|
|
The domain name of the load balancer certificate. This will be
|
|
`aws_acm_certificate.example.domain_name` if you are using the examples from this page.
|
|
|
|
### Create an IAM policy for OIDC Federated Users
|
|
|
|
Use the [`aws_iam_role` resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role)
|
|
to create an appropriate IAM role for workloads acting as federated users. This will be
|
|
specific to your use case. The following example allows workloads access to S3 buckets.
|
|
|
|
```hcl
|
|
# Variables for OIDC provider and AWS account
|
|
variable "oidc_provider" {
|
|
description = "The OIDC provider URL"
|
|
type = string
|
|
default = "<DOMAIN_NAME>"
|
|
}
|
|
|
|
variable "aws_account_id" {
|
|
description = "AWS account ID"
|
|
type = string
|
|
default = "<AWS_ACCOUNT_ID>"
|
|
}
|
|
|
|
data "aws_iam_policy_document" "assume_role" {
|
|
statement {
|
|
effect = "Allow"
|
|
|
|
principals {
|
|
type = "Federated"
|
|
identifiers = ["arn:aws:iam::${var.aws_account_id}:oidc-provider/${var.oidc_provider}"]
|
|
}
|
|
|
|
actions = ["sts:AssumeRoleWithWebIdentity"]
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "${var.oidc_provider}:aud"
|
|
values = ["aws"]
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create an IAM role with the assume role policy generated above
|
|
resource "aws_iam_role" "s3_all_access_role" {
|
|
name = "s3_all_access_role"
|
|
assume_role_policy = data.aws_iam_policy_document.assume_role.json
|
|
|
|
tags = {
|
|
tag-key = "tag-value"
|
|
}
|
|
}
|
|
|
|
# Inline policy that defines what the role can do (full S3 access)
|
|
data "aws_iam_policy_document" "s3_access_policy" {
|
|
statement {
|
|
effect = "Allow"
|
|
|
|
actions = [
|
|
"s3:*",
|
|
"s3-object-lambda:*"
|
|
]
|
|
|
|
resources = ["*"] # You can scope this down to specific S3 buckets if necessary
|
|
}
|
|
}
|
|
|
|
# Create a policy resource from the inline policy document above
|
|
resource "aws_iam_policy" "policy" {
|
|
name = "nomad-oidc-policy"
|
|
description = "A policy for federated Nomad OIDC"
|
|
policy = data.aws_iam_policy_document.s3_access_policy.json
|
|
}
|
|
|
|
# Attach the S3 access policy to the IAM role
|
|
resource "aws_iam_role_policy_attachment" "test-attach" {
|
|
role = aws_iam_role.s3_all_access_role.name
|
|
policy_arn = aws_iam_policy.policy.arn
|
|
}
|
|
```
|
|
|
|
This configuration requires the following information:
|
|
- [`<DOMAIN_NAME>`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_zone#name):
|
|
The domain name of your Nomad cluster without the protocol or port.
|
|
- `<AWS_ACCOUNT_ID>`: The ID of the AWS account where the IAM role from the previous step was
|
|
created.
|
|
|
|
## Update the Nomad server configuration
|
|
|
|
After you configure AWS, modify the Nomad server configuration file. Add the
|
|
[`oidc_issuer` attribute](/nomad/docs/configuration/server#oidc_issuer) and set the value
|
|
to the domain name for the Nomad cluster. This [enables the HTTP endpoint in Nomad](https://developer.hashicorp.com/nomad/docs/configuration/server#oidc_issuer) that allows third parties to discover Nomad's OIDC
|
|
configuration.
|
|
|
|
```hcl
|
|
server {
|
|
enabled = true
|
|
[...]
|
|
oidc_issuer = "https://<DOMAIN_NAME>"
|
|
[...]
|
|
}
|
|
```
|
|
|
|
This configuration requires the following information:
|
|
- `<DOMAIN_NAME>`: The domain name of your Nomad cluster without the protocol or port.
|
|
|
|
Restart the Nomad server agent to apply the configuration changes.
|
|
|
|
## Create and run a sample jobspec file
|
|
|
|
Create and run a jobspec file to validate your configuration. The following file is named `s3-upload.nomad.hcl`, add the following configuration to it, and
|
|
save the file.
|
|
|
|
```hcl
|
|
job "s3" {
|
|
type = "batch"
|
|
group "bucket" {
|
|
task "copy" {
|
|
driver = "docker"
|
|
config {
|
|
image = "public.ecr.aws/aws-cli/aws-cli"
|
|
command = "s3"
|
|
args = ["cp", "/local/test.txt", "s3://<S3_BUCKET_NAME>/test-nomad.txt"]
|
|
}
|
|
|
|
identity {
|
|
name = "aws"
|
|
aud = ["aws"]
|
|
file = true
|
|
ttl = "1h"
|
|
|
|
# AWS SDKs gracefully handle OIDC/WebIdentity reauthentication when the
|
|
# session or token expire, therefore a restart isn't needed
|
|
change_mode = "noop"
|
|
}
|
|
|
|
template {
|
|
destination = "local/test.txt"
|
|
change_mode = "restart"
|
|
data = <<EOF
|
|
Job: {{ env "NOMAD_JOB_NAME" }}
|
|
Alloc: {{ env "NOMAD_ALLOC_ID" }}
|
|
EOF
|
|
}
|
|
|
|
env {
|
|
AWS_ROLE_ARN = "arn:aws:iam::<AWS_ACCOUNT_ID>:role/<IAM_ROLE_NAME>"
|
|
# The format of the token file is nomad_$NAME_OF_IDENTITY.jwt
|
|
AWS_WEB_IDENTITY_TOKEN_FILE = "${NOMAD_SECRETS_DIR}/nomad_aws.jwt"
|
|
}
|
|
|
|
resources {
|
|
cpu = 500
|
|
memory = 256
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
This configuration requires the following information:
|
|
- `<S3_BUCKET_NAME>`: The name of the S3 bucket where the test file will be saved.
|
|
- `<AWS_ACCOUNT_ID>`: The ID of the AWS account where the IAM role from the previous step was
|
|
created.
|
|
- `<IAM_ROLE_NAME>`: The name of the IAM role from previous steps. This will be
|
|
`s3_all_access_role` if you are using the examples from this page.
|
|
|
|
Submit the job to Nomad.
|
|
|
|
```shell-session
|
|
$ nomad job run s3-upload.nomad.hcl
|
|
```
|
|
|
|
Verify that the job completed successfully.
|
|
|
|
```shell-session
|
|
$ nomad job status s3
|
|
```
|
|
|
|
Verify that the file was also uploaded to the S3 bucket.
|
|
|
|
|
|
[Workload Identity]: /nomad/docs/concepts/workload-identity
|
|
[OpenID Connect Provider]: https://openid.net/developers/how-connect-works/
|