Details#
Networking#
The template creates a VPC with public and private subnets across two availability zones. EKS nodes run in private subnets; the Network Load Balancer (NLB) sits in public subnets and forwards TCP/443 to Traefik pods.
Amazon Route 53 manages DNS. The template references a Hosted Zone for your domain (which must already exist) and relies on external-dns to create DNS records pointing your subdomain to the NLB.
cert-manager obtains TLS certificates from Let’s Encrypt using the DNS-01 challenge via Route 53.
Compute#
The template creates EKS managed node groups with role-based scheduling:
components — Platform infrastructure pods (operator, router, cert-manager, external-dns). Labeled
jupyter-deploy/role=components.workspaces — User workspace pods. Labeled
jupyter-deploy/role=workspaces.
Each node group auto-detects the appropriate EKS-optimized AMI type from the instance family:
CPU x86_64 instances → AL2023_x86_64_STANDARD
CPU arm64 instances → AL2023_ARM_64_STANDARD
GPU x86_64 instances → AL2023_x86_64_NVIDIA
Neuron instances → AL2023_x86_64_NEURON
You can also set an explicit ami_type value per node group.
Node group sizing and how capacity scales are covered in AutoScaling.
Application Images#
The template optionally creates infrastructure for building custom workspace images:
ECR repository — One repository per application type (e.g.
jupyterlab-v1.0.0). Stores the built container images.CodeBuild project — Builds Dockerfiles from the
applications/directory in your project and pushes to ECR.IAM role — CodeBuild service role with permissions for ECR push and CloudWatch Logs.
The JupyterLab application image is built automatically on first deploy when workspace_app_jupyterlab_use = true.
Access and Permissions#
Access to the cluster is governed at two layers: IAM controls who can reach the Kubernetes API and administer the cluster, and RBAC controls what authenticated GitHub teams can do with workspaces. Team sign-in itself goes through GitHub OAuth via Dex — see Prerequisites for granting teams access.
IAM#
The template creates several IAM roles:
Cluster role — Used by the EKS control plane.
Node roles — One per node group, with managed policies for ECR pull, EKS worker nodes, and CNI.
Pod identity associations — cert-manager and external-dns use EKS Pod Identity for Route 53 and DNS access.
Admin access entries — The caller’s IAM principal is always authorized; roles in
admin_role_namesand users inadmin_user_namesget cluster admin permissions and workspace admin group membership.
Helm charts#
Three Helm releases are installed:
Chart |
Namespace |
Purpose |
|---|---|---|
traefik-crds |
Router namespace |
Traefik CRDs (IngressRoute, Middleware, etc.) |
jupyter-k8s |
Operator namespace |
Workspace operator, extension API server, CRDs |
jupyter-k8s-aws-oidc |
Router namespace |
Traefik, Dex, OAuth2 Proxy, Authmiddleware |
Charts are pulled from OCI registries. The chart versions and OCI references are configurable for testing against staging registries.
RBAC#
The template deploys a github-rbac local chart that creates namespace-scoped Role and RoleBinding resources:
Each namespace in
workspace_rbac_namespacesgets a Role granting workspace CRUD permissions.RoleBindings associate the Role with GitHub teams from
oauth_allowed_teams.The same teams get a read-only (
get/list) Role inworkspace_shared_namespacefor discovering sharedWorkspaceTemplateandWorkspaceAccessStrategyresources.Roles in
admin_role_namesand users inadmin_user_namesadditionally get acluster-workspace-adminClusterRoleBinding for cross-namespace workspace management.
Presets#
The template provides two variable presets:
defaults-all.tfvars— comprehensive preset with all recommended values (prompts only for domain, subdomain, OAuth credentials, and teams)defaults-base.tfvars— minimal preset that additionally prompts for node group configuration
Requirements#
Name |
Version |
|---|---|
terraform |
>= 1.6 |
aws |
>= 5.0 |
kubernetes |
>= 2.0 |
helm |
>= 2.0 |
Providers#
Name |
Purpose |
|---|---|
aws |
AWS resource management |
kubernetes |
Kubernetes resources (RBAC, namespaces) |
helm |
Helm chart installation |
null |
Provisioners for build triggers and health waits |
Terraform Modules#
Name |
Location |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Inputs#
Name |
Type |
Default |
Description |
|---|---|---|---|
cluster_name_prefix |
|
|
Prefix for the EKS cluster name (template appends a unique suffix) |
region |
|
|
AWS region where to deploy the resources |
kubernetes_version |
|
|
Kubernetes version for the EKS cluster |
domain |
|
Required |
Domain name for workspace URLs (must have a Route 53 hosted zone) |
subdomain |
|
Required |
Subdomain prefix for workspace URLs |
letsencrypt_email |
|
Required |
Email for Let’s Encrypt certificate expiration notices |
oauth_app_client_id |
|
Required |
Client ID of the GitHub OAuth app |
oauth_app_client_secret |
|
Required |
Client secret of the GitHub OAuth app |
oauth_allowed_teams |
|
Required |
GitHub teams to allow access, in |
node_groups |
|
See preset |
EKS managed node groups (name, role, instance_type, disk_size_gb, sizing) |
workspace_rbac_namespaces |
|
|
Namespaces where teams get workspace permissions |
admin_role_names |
|
|
IAM role names to grant cluster and workspace admin (list all callers for stable state) |
admin_user_names |
|
|
IAM user names to grant cluster and workspace admin (list all callers for stable state) |
cluster_log_retention_days |
|
|
Days to retain EKS cluster CloudWatch logs |
custom_tags |
|
|
Tags added to all AWS resources |
workspace_operator_namespace |
|
|
Namespace for the workspace operator |
workspace_router_namespace |
|
|
Namespace for routing components |
workspace_shared_namespace |
|
|
Namespace for shared workspace resources |
workspace_operator_chart_oci |
|
See preset |
OCI reference for the jupyter-k8s Helm chart |
workspace_operator_chart_version |
|
See preset |
Version of the jupyter-k8s chart |
workspace_router_chart_oci |
|
See preset |
OCI reference for the aws-oidc router chart |
workspace_router_chart_version |
|
See preset |
Version of the aws-oidc chart |
traefik_crd_chart_version |
|
|
Version of the Traefik CRDs chart |
workspaces_default_access_type |
|
|
Default access type for new workspaces ( |
workspaces_default_ownership_type |
|
|
Default ownership type for new workspaces |
workspaces_idle_shutdown_enabled |
|
|
Enable automatic idle shutdown for workspaces |
workspaces_idle_shutdown_timeout_default |
|
|
Default idle timeout in minutes (5-1440) |
workspaces_idle_shutdown_timeout_min |
|
|
Minimum idle timeout users can set (advanced; lower values mainly serve testing) |
workspaces_idle_shutdown_timeout_max |
|
|
Maximum idle timeout users can set (15-1440) |
workspace_app_jupyterlab_use |
|
|
Build and deploy the JupyterLab workspace image |
workspace_app_jupyterlab_app_type |
|
|
Application type identifier for the workspace template |
workspace_app_jupyterlab_image_name |
|
See preset |
ECR repository name for the JupyterLab image |
workspace_app_jupyterlab_image_build |
|
|
Build tag (increment to trigger rebuild) |
Outputs#
Name |
Description |
|---|---|
|
Name of the EKS cluster |
|
API server endpoint URL for the EKS cluster |
|
ARN of the EKS cluster |
|
Base64-encoded CA certificate for the EKS cluster |
|
AWS region where the cluster is deployed |
|
Unique deployment identifier |
|
ID of the VPC hosting the EKS cluster |
|
Kubernetes namespace for the workspace operator controller |
|
Kubernetes namespace for routing components |
|
Kubernetes namespace for shared workspace resources |
|
Base URL for workspace access |
|
URL to the web UI |
|
ARN of the Secrets Manager secret storing the OAuth app client secret |
|
ECR image URI for the JupyterLab workspace image |
|
Path to the local kubeconfig file for this cluster |