Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e343196
WIP: Enable bucket versioning
nss10 Jul 7, 2026
efdeabb
[UNTESTED]Add initial s3files setup + separate out s3 files into a ne…
nss10 Jul 21, 2026
41926ab
Update EKS security group filter to use EKS group name
nss10 Jul 21, 2026
6e9abd5
Update docstring
nss10 Jul 21, 2026
6e368cd
Add a TODO comment regarding security group creation, maybe can reduc…
nss10 Jul 21, 2026
f4f2b75
Fix minor bugs and add more TODOs.
nss10 Jul 21, 2026
0248c3d
Add file system status implementation and waiter
nss10 Jul 22, 2026
e172079
Update import path
nss10 Jul 22, 2026
73ad87c
Move boto3 clients to a different file to avoid circular imports
nss10 Jul 22, 2026
1ac0aa4
Update exception type
nss10 Jul 22, 2026
f363791
Fix get_s3_files_system and add/update TODO comments
nss10 Jul 22, 2026
15182e5
Create dynamic IAM role for S3Files
nss10 Jul 23, 2026
fbc7545
Add STORAGE_TYPE config variable, add documentation for s3files
nss10 Jul 23, 2026
80cd425
Make S3Files a configurable setup
nss10 Jul 23, 2026
0eaf83e
Merge branch 'master' into feat/s3Files
nss10 Jul 23, 2026
2cf8c10
Make mount target provisioning a bgTask + Update docs
nss10 Jul 23, 2026
fc32d15
Update comments
nss10 Jul 23, 2026
bb84de3
Add missing function call.
nss10 Jul 23, 2026
df89174
Add more comments
nss10 Jul 24, 2026
00f569f
Re-organize aws_utils into aws.bucket, aws.aws_utils, aws.clients. (T…
nss10 Jul 24, 2026
3f56313
Fix patching in unit tests. All current tests pass
nss10 Jul 24, 2026
28614f8
Add more TODOs
nss10 Jul 24, 2026
aeb3071
Add unit tests for S3Files
nss10 Jul 27, 2026
3dd0630
Add fixes related to review comments
nss10 Jul 29, 2026
db7fd5e
Fix lint errors in unit tests
nss10 Jul 29, 2026
44e8406
Fix more PR suggestions and add more unit tests
nss10 Jul 29, 2026
039af05
Merge branch 'master' of https://github.com/uc-cdis/gen3-workflow int…
nss10 Jul 29, 2026
fed3b31
Fix lint issues
nss10 Jul 29, 2026
c6d7202
Make security group field configurable and add docs on how to fetch them
nss10 Jul 30, 2026
1e45803
Update the link in config.py
nss10 Jul 30, 2026
6f9c69e
remove TODO comment
nss10 Jul 30, 2026
bc4e9b8
Remove unused imports
nss10 Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions docs/s3Files.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# S3 Files Setup

## Overview
TES worker and executor pods use **S3 Files** (Amazon's EFS-backed service) to interact with a user's S3 bucket. While pod lifecycle is managed by the underlying execution engine (Funnel), Gen3Workflow is responsible for provisioning the supporting AWS resources — file systems, mount targets, IAM roles, and security groups — required for S3 Files to function.

## Enabling S3 Files
Set the following in your config:

```yaml
ENABLE_S3_FILES: true
```

For Helm-based deployments, set:

```yaml
{{ .Values.gen3WorkflowConfig.enableS3Files }}: true
```

## Prerequisites
* Gen3Workflow must be deployed on an EKS cluster.
* The EKS cluster must support S3 Files, provisioned via the [EFS CSI driver](https://github.com/kubernetes-sigs/aws-efs-csi-driver).


#### NOTE:
* Currently Gen3Workflow with S3Files only supports user bucket and the EKS cluster being present in the same region. Support shall be added in the future.


### Determining the EKS Security Group Names for S3 Files Setup

`gen3-workflow` needs the names of the EKS security groups attached to the nodes that run workflow tasks, in order to allow S3 Files mount targets network access. These are currently **not derivable programmatically** and must be looked up manually per cluster, then set as config values.

**Steps for a Gen3 operator:**

1. **Identify the node role(s) workflow tasks run on** for this environment. In most clusters this is `role=workflow` (and `role=gpu` if GPU tasks are supported). Check the cluster's `gen3-gitops` `cluster-values.yaml` for how these roles are configured, since role → security-group mapping can differ per environment.

2. **Find the Karpenter `EC2NodeClass` for each relevant role** in `gen3-helm` under `helm/cluster-level-resources/templates/karpenter-config-resources-<role>.yaml` (e.g. `karpenter-config-resources-workflow.yaml`). Look at the `securityGroupSelectorTerms` block — nodes get whichever security groups carry the matching `karpenter.sh/discovery` tag value (`selectorTag` from Helm values).

3. **Query AWS for the security groups carrying that discovery tag**, scoped to the cluster's VPC:
```
aws ec2 describe-security-groups \
--filters "Name=tag:karpenter.sh/discovery,Values=<selectorTag>" \
--query "SecurityGroups[].{Name:GroupName,Id:GroupId}"
```

4. **Manually identify the "main" security group** from the results — the one that actually holds the cluster's inbound/outbound networking rules (as opposed to any minimal/placeholder groups also carrying the tag). This step is judgment-based today; usually the one with most inbound and outbound rules.

5. Repeat for each role that can run workflow tasks. Note: in `devplanetv2`, nodes labeled `role=workflow` carry the same discovery tag as jupyter nodes, so the jupyter security group ends up governing traffic for workflow nodes — check whether your cluster has the same overlap before assuming you only need one SG name.

6. Set the resulting security group name(s) in the `gen3-workflow` config under the field `EKS_SECURITY_GROUP_NAMES`.

> **Known limitation:** this is a temporary, manually-maintained workaround. The long-term plan is to move nodepool (and likely security group) creation into `gen3-workflow` itself once per-user nodepools are implemented, at which point this lookup process should be revisited/removed.
67 changes: 67 additions & 0 deletions gen3workflow/aws/aws_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import json
from typing import Union
from gen3workflow.config import config


def dict_to_sorted_json_str(obj: dict) -> str:
"""
Reads a Python dict and returns a JSON string with ordered keys
Use case: when comparing JSON objects returned by AWS, comparisons are deterministic and less flaky
"""
return json.dumps(obj, sort_keys=True, separators=(",", ":"))


def get_safe_name_from_hostname(
user_id: Union[str, None], reserved_length: int = 0
) -> str:
"""
Generate a valid and length-safe name (for IAM user, S3 bucket, or IAM role)
derived from the configured hostname and optional user ID.
Rules:
- IAM user names: up to 64 characters.
- S3 bucket / IAM role names: up to 63 characters.
- Only alphanumeric characters and the following are allowed: +=,.@_-
(assumes HOSTNAME and user IDs are already compliant).
Args:
user_id (str | None): The user's unique Gen3 ID. If None, will not be included in the safe name.
reserved_length (int): Number of characters to reserve for prefixes/suffixes.

Returns:
str: safe name
"""
escaped_hostname = config["HOSTNAME"].replace(".", "-")
safe_name = f"gen3wf-{escaped_hostname}"
max_chars = 63 - reserved_length
if user_id:
max_chars = max_chars - len(f"-{user_id}")
if len(safe_name) > max_chars:
safe_name = safe_name[:max_chars]
if user_id:
safe_name = f"{safe_name}-{user_id}"
return safe_name


def get_worker_sa_name(user_id: str) -> str:
"""
Generate the name of the Kubernetes service account used by worker pods for the specified user.

Args:
user_id (str): The user's unique Gen3 ID
Returns:
str: service account name
"""
safe_name = get_safe_name_from_hostname(user_id, reserved_length=len("-worker-sa"))
return f"{safe_name}-worker-sa"


def get_bucket_name_from_user_id(user_id: str) -> str:
"""
Generate the S3 bucket name for the specified user.

Args:
user_id (str): The user's unique Gen3 ID
Returns:
str: S3 bucket name
"""
# Abstracted for future flexibility — currently same as safe name.
return get_safe_name_from_hostname(user_id)
Loading
Loading