Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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
1 change: 1 addition & 0 deletions docs/docs/how-tos/nebari-gcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ management.

If it's your first time creating a service account, please follow
[these detailed instructions](https://cloud.google.com/iam/docs/creating-managing-service-accounts) to create a Google Service Account with the following roles attached:

- [`roles/editor`](https://cloud.google.com/iam/docs/understanding-roles#editor)
- [`roles/resourcemanager.projectIamAdmin`](https://cloud.google.com/iam/docs/understanding-roles#resourcemanager.projectIamAdmin)
- [`roles/container.admin`](https://cloud.google.com/iam/docs/understanding-roles#container.admin)
Expand Down
136 changes: 136 additions & 0 deletions docs/docs/references/container-sources.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylergraff
The tested updates for featuring a nebari-config.yaml that enables options to override, exhaustively, every Nebari container image were never merged for the following reasons:

  • A more concise approach for mirroring images is available using containerD config overrides/imports, which does not require specifying the mirrored name for each individual container in nebari-config.yaml
  • Discussion took place regarding possible migration from Helm to kustomize and kustomization files, which could deem the terraform/helm override method of mirroring obsolete.

We took a different approach towards mirroring container images based on pointing to default mirrors for private registries (e.g. ECR, GitLab, etc.) as overrides/imports to the EKS nodes' containerD configs.
The enabling PR for this approach was PR#2668, which added the feature to run pre_bootstrap_command on nodes.

The following config options are examples of mirroring container images by means of customizing ContainerD at the k8s node:

# Set ECR as default container registry mirror
amazon_web_services:
  node_groups:
    general:
      instance: m5.2xlarge
      min_nodes: 1
      max_nodes: 1
      gpu: false
      single_subnet: false
      permissions_boundary:
      launch_template:
        pre_bootstrap_command: |
            #!/bin/bash
            # Verify that IP forwarding is enabled for worker nodes, as is required for containerd
            if [[ $(sysctl net.ipv4.ip_forward | grep "net.ipv4.ip_forward = 1") ]]; then echo "net.ipv4.ip_forward is on"; else sysctl -w net.ipv4.ip_forward=1; fi
            # Set ECR as default container registry mirror
            mkdir -p /etc/containerd/certs.d/_default
            ECR_TOKEN="$(aws ecr get-login-password --region us-east-1)"
            BASIC_AUTH="$(echo -n "AWS:$ECR_TOKEN" | base64 -w 0)"
            cat <<-EOT > /etc/containerd/certs.d/_default/hosts.toml
            [host."https://xxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com"]
              capabilities = ["pull", "resolve"]
              [host."https://xxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com".header]
                authorization = "Basic $BASIC_AUTH"
            EOT


# Set GitLab CR as default container registry mirror in hosts.toml; 
# must have override_path set if project/group names don't match upstream container
amazon_web_services:
  node_groups:
    general:
      instance: m5.2xlarge
      min_nodes: 1
      max_nodes: 1
      gpu: false
      single_subnet: false
      permissions_boundary:
      launch_template:
        pre_bootstrap_command: |
            #!/bin/bash
            # Verify that IP forwarding is enabled for worker nodes, as is required for containerd
            if [[ $(sysctl net.ipv4.ip_forward | grep "net.ipv4.ip_forward = 1") ]]; then echo "net.ipv4.ip_forward is on"; else sysctl -w net.ipv4.ip_forward=1; fi
            # Set default container registry mirror in hosts.toml; must have override_path set if project/group names don't match upstream container
            CONTAINER_REGISTRY_URL="gitlab-registry.link.net"
            CONTAINER_REGISTRY_USERNAME="project_2744_bot_xxxxxxxxxxxxxx"
            CONTAINER_REGISTRY_TOKEN="xxxxxxxxxxx"
            CONTAINER_REGISTRY_GROUP=as-nebari
            CONTAINER_REGISTRY_PROJECT=nebari-test
            mkdir -p /etc/containerd/certs.d/_default
            cat <<-EOT > /etc/containerd/certs.d/_default/hosts.toml
            [host."https://$CONTAINER_REGISTRY_URL/v2/$CONTAINER_REGISTRY_GROUP/$CONTAINER_REGISTRY_PROJECT"]
              override_path = true
              capabilities = ["pull", "resolve"]
            EOT
            # Set containerd registry config auth in config.d .toml import dir
            mkdir -p /etc/containerd/config.d
            cat <<EOT | sudo tee /etc/containerd/config.d/config-import.toml
            version = 2
            [plugins."io.containerd.grpc.v1.cri".registry]
              config_path = "/etc/containerd/certs.d:/etc/docker/certs.d"
              [plugins."io.containerd.grpc.v1.cri".registry.auths]
              [plugins."io.containerd.grpc.v1.cri".registry.configs]
                [plugins."io.containerd.grpc.v1.cri".registry.configs."$CONTAINER_REGISTRY_URL".auth]
                  username = "$CONTAINER_REGISTRY_USERNAME"
                  password = "$CONTAINER_REGISTRY_TOKEN"
            EOT


# Set GitLab CR as default container registry mirror in hosts.toml; 
# must have override_path set if project/group names don't match upstream container
# Also add/set GitLab Client SSL/TLS Certificate for Containerd
amazon_web_services:
  node_groups:
    general:
      instance: m5.2xlarge
      min_nodes: 1
      max_nodes: 1
      gpu: false
      single_subnet: false
      permissions_boundary:
      launch_template:
        pre_bootstrap_command: |
            #!/bin/bash
            # Verify that IP forwarding is enabled for worker nodes, as is required for containerd
            if [[ $(sysctl net.ipv4.ip_forward | grep "net.ipv4.ip_forward = 1") ]]; then echo "net.ipv4.ip_forward is on"; else sysctl -w net.ipv4.ip_forward=1; fi
            # Set default container registry mirror in hosts.toml; must have override_path set if project/group names don't match upstream container
            CONTAINER_REGISTRY_URL="gitlab-registry.link.net"
            CONTAINER_REGISTRY_USERNAME="project_2744_bot_xxxxxxxxxxxxxx"
            CONTAINER_REGISTRY_TOKEN="xxxxxxxxxxx"
            CONTAINER_REGISTRY_GROUP=as-nebari
            CONTAINER_REGISTRY_PROJECT=nebari-test
            mkdir -p /etc/containerd/certs.d/_default
            cat <<-EOT > /etc/containerd/certs.d/_default/hosts.toml
            [host."https://$CONTAINER_REGISTRY_URL/v2/$CONTAINER_REGISTRY_GROUP/$CONTAINER_REGISTRY_PROJECT"]
              override_path = true
              capabilities = ["pull", "resolve"]
              client = ["/etc/containerd/certs.d/$CONTAINER_REGISTRY_URL/client.pem"]
            EOT
            # Set containerd registry config auth in config.d .toml import dir
            mkdir -p /etc/containerd/config.d
            cat <<EOT | sudo tee /etc/containerd/config.d/config-import.toml
            version = 2
            [plugins."io.containerd.grpc.v1.cri".registry]
              config_path = "/etc/containerd/certs.d:/etc/docker/certs.d"
              [plugins."io.containerd.grpc.v1.cri".registry.auths]
              [plugins."io.containerd.grpc.v1.cri".registry.configs]
                [plugins."io.containerd.grpc.v1.cri".registry.configs."$CONTAINER_REGISTRY_URL".auth]
                  username = "$CONTAINER_REGISTRY_USERNAME"
                  password = "$CONTAINER_REGISTRY_TOKEN"
            EOT
            # Add client key/cert to containerd
            mkdir -p /etc/containerd/certs.d/$CONTAINER_REGISTRY_URL
            cat <<-EOT >> /etc/containerd/certs.d/$CONTAINER_REGISTRY_URL/client.pem
            -----BEGIN CERTIFICATE-----
            XzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzZx
            ZxyzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzXz
            -----END CERTIFICATE-----
            -----BEGIN PRIVATE KEY-----
            XzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzZx
            ZxyzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzXz
            -----END PRIVATE KEY-----
            EOT

Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
## Deploying and Running Nebari from a Private Container Repository

Nebari deploys and runs FOSS components as containers running in Kubernetes.
By default, Nebari sources each container from the container's respective public repository, typically `docker.io` or `quay.io`.
This introduces supply-chain concerns for security-focused customers.

One solution to these supply-chain concerns is to deploy Nebari from private locally-mirrored containers:

- Create a controlled private container repository (e.g. ECR)
- Mirror all containers used by Nebari into this private container repository
- Use the `pre_bootstrap_command` mechanism in `nebari-config.yaml` to specify the mirrored container repo

Deploying Nebari in this fashion eliminates significant supply chain surface-area, but requires identifying all containers used by Nebari.

The following configurations demonstrate how to specify a private repo denoted by the string `[PRIVATE_REPO]`.

### Set ECR as default container registry mirror

```
amazon_web_services:
node_groups:
general:
instance: m5.2xlarge
launch_template:
pre_bootstrap_command: |
#!/bin/bash
# Verify that IP forwarding is enabled for worker nodes, as is required for containerd
if [[ $(sysctl net.ipv4.ip_forward | grep "net.ipv4.ip_forward = 1") ]]; then echo "net.ipv4.ip_forward is on"; else sysctl -w net.ipv4.ip_forward=1; fi
# Set ECR as default container registry mirror
mkdir -p /etc/containerd/certs.d/_default
ECR_TOKEN="$(aws ecr get-login-password --region us-east-1)"
BASIC_AUTH="$(echo -n "AWS:$ECR_TOKEN" | base64 -w 0)"
cat <<-EOT > /etc/containerd/certs.d/_default/hosts.toml
[host."https://[PRIVATE_REPO].dkr.ecr.us-east-1.amazonaws.com"]
capabilities = ["pull", "resolve"]
[host."https://[PRIVATE_REPO].dkr.ecr.us-east-1.amazonaws.com".header]
authorization = "Basic $BASIC_AUTH"
EOT

```

### Set GitLab CR as default container registry mirror

```
# Set GitLab CR as default container registry mirror in hosts.toml;
# must have override_path set if project/group names don't match upstream container
amazon_web_services:
node_groups:
general:
instance: m5.2xlarge
launch_template:
pre_bootstrap_command: |
#!/bin/bash
# Verify that IP forwarding is enabled for worker nodes, as is required for containerd
if [[ $(sysctl net.ipv4.ip_forward | grep "net.ipv4.ip_forward = 1") ]]; then echo "net.ipv4.ip_forward is on"; else sysctl -w net.ipv4.ip_forward=1; fi
# Set default container registry mirror in hosts.toml; must have override_path set if project/group names don't match upstream container
CONTAINER_REGISTRY_URL="[PRIVATE_REPO]"
CONTAINER_REGISTRY_USERNAME="[username]"
CONTAINER_REGISTRY_TOKEN="[token]"
CONTAINER_REGISTRY_GROUP=as-nebari
CONTAINER_REGISTRY_PROJECT=nebari-test
mkdir -p /etc/containerd/certs.d/_default
cat <<-EOT > /etc/containerd/certs.d/_default/hosts.toml
[host."https://$CONTAINER_REGISTRY_URL/v2/$CONTAINER_REGISTRY_GROUP/$CONTAINER_REGISTRY_PROJECT"]
override_path = true
capabilities = ["pull", "resolve"]
EOT

# Set containerd registry config auth in config.d .toml import dir
mkdir -p /etc/containerd/config.d
cat <<EOT | sudo tee /etc/containerd/config.d/config-import.toml
version = 2
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d:/etc/docker/certs.d"
[plugins."io.containerd.grpc.v1.cri".registry.auths]
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."$CONTAINER_REGISTRY_URL".auth]
username = "$CONTAINER_REGISTRY_USERNAME"
password = "$CONTAINER_REGISTRY_TOKEN"
EOT
```

### Set GitLab CR as default container registry mirror, with custom Client SSL/TLS Certs

```
# must have override_path set if project/group names don't match upstream container
# Also add/set GitLab Client SSL/TLS Certificate for Containerd
amazon_web_services:
node_groups:
general:
instance: m5.2xlarge
launch_template:
pre_bootstrap_command: |
#!/bin/bash
# Verify that IP forwarding is enabled for worker nodes, as is required for containerd
if [[ $(sysctl net.ipv4.ip_forward | grep "net.ipv4.ip_forward = 1") ]]; then echo "net.ipv4.ip_forward is on"; else sysctl -w net.ipv4.ip_forward=1; fi
# Set default container registry mirror in hosts.toml; must have override_path set if project/group names don't match upstream container
CONTAINER_REGISTRY_URL="[PRIVATE_REPO]"
CONTAINER_REGISTRY_USERNAME="[username]"
CONTAINER_REGISTRY_TOKEN="[token]"
CONTAINER_REGISTRY_GROUP=as-nebari
CONTAINER_REGISTRY_PROJECT=nebari-test
mkdir -p /etc/containerd/certs.d/_default
cat <<-EOT > /etc/containerd/certs.d/_default/hosts.toml
[host."https://$CONTAINER_REGISTRY_URL/v2/$CONTAINER_REGISTRY_GROUP/$CONTAINER_REGISTRY_PROJECT"]
override_path = true
capabilities = ["pull", "resolve"]
client = ["/etc/containerd/certs.d/$CONTAINER_REGISTRY_URL/client.pem"]
EOT

# Set containerd registry config auth in config.d .toml import dir
mkdir -p /etc/containerd/config.d
cat <<EOT | sudo tee /etc/containerd/config.d/config-import.toml
version = 2
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d:/etc/docker/certs.d"
[plugins."io.containerd.grpc.v1.cri".registry.auths]
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."$CONTAINER_REGISTRY_URL".auth]
username = "$CONTAINER_REGISTRY_USERNAME"
password = "$CONTAINER_REGISTRY_TOKEN"
EOT

# Add client key/cert to containerd
mkdir -p /etc/containerd/certs.d/$CONTAINER_REGISTRY_URL
cat <<-EOT >> /etc/containerd/certs.d/$CONTAINER_REGISTRY_URL/client.pem
-----BEGIN CERTIFICATE-----
XzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzZx
ZxyzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzXz
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
XzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzZx
ZxyzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzXz
-----END PRIVATE KEY-----
EOT
```
69 changes: 69 additions & 0 deletions docs/docs/references/enhanced-security.md
Copy link
Contributor

@joneszc joneszc Oct 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylergraff
The following feature, although tested, was never merged
Lines 9-15

amazon_web_services:
  ec2_keypair_name: [example_keypair_name] # Name, not ARN

The following feature amazon_web_services.extra_ssl_certificates was tested but not merged:
Lines 17-28

  extra_ssl_certificates: |
    -----BEGIN CERTIFICATE-----
    MIIF...<snip>...ABCD
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    MIIF...<snip>...EF01
    -----END CERTIFICATE-----

...Instead, the same feature can be implemented since PR#2668 as follows:

# Add client certificate to CA trust on node
amazon_web_services:
  node_groups:
    general:
      instance: m5.2xlarge
      min_nodes: 1
      max_nodes: 1
      gpu: false
      single_subnet: false
      permissions_boundary:
      launch_template:
        pre_bootstrap_command: |
            #!/bin/bash
            cat <<-EOT >> /etc/pki/ca-trust/source/anchors/client.pem
            -----BEGIN CERTIFICATE-----
            XzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzZx
            ZxyzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzXz
            -----END CERTIFICATE-----
            EOT
            sudo update-ca-trust extract

Also, the Private EKS endpoint configuration feauture (Lines 30-36) was implemented in PR#2618 but needs to be configured as follows, with a string value as 1 of [public, private, public_and_private]:

amazon_web_services:
  eks_endpoint_access: private

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
## Nebari Security Considerations

The security of _AWS Nebari_ deployments can be enhanced through the following deployment configuration options in `nebari-config.yaml`:

- **Explicit definition of container sources**
This option allows for the use of locally mirrored, security-hardened, or otherwise customized container images in place of the containers used by default.
See: [container-sources](container-sources.md)

- **Definition of an ssh key that can access EKS hosts**
EKS hosts by default cannot be accessed via ssh. This configuration item allows ssh access into EKS hosts, which can be useful for troubleshooting or external monitoring and auditing purposes.

```
amazon_web_services:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylergraff
The following feature, although tested, was never merged
Lines 9-15

amazon_web_services:
  ec2_keypair_name: [example_keypair_name] # Name, not ARN

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed!

ec2_keypair_name: [example_keypair_name] # Name, not ARN
```

- **Installation of custom SSL certificate(s) into EKS hosts**
Install private certificates used by (e.g.) in-line content inspection engines which re-encrypt traffic.

```
# Add client certificate to CA trust on node
amazon_web_services:
node_groups:
general:
instance: m5.2xlarge
launch_template:
pre_bootstrap_command: |
#!/bin/bash
cat <<-EOT >> /etc/pki/ca-trust/source/anchors/client.pem
-----BEGIN CERTIFICATE-----
XzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzZx
ZxyzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxxzxzxzxzxzxzxzxzxzxxzxzXz
-----END CERTIFICATE-----
EOT
sudo update-ca-trust extract
```

- **Private EKS endpoint configuration**
Mirrors the corresponding AWS console option, which routes all EKS traffic within the VPC.

```
amazon_web_services:
eks_endpoint_access: private # valid values: [public, private, public_and_private]
```

- **Deploy into existing subnets**
Instructs Nebari to be deployed into existing subnets, rather than creating its own new subnets.

```
existing_subnet_ids:
- subnet-0123456789abcdef
- subnet-abcdef0123456789
existing_security_group_id: sg-0123456789abcdef
ingress:
terraform_overrides:
load-balancer-annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylergraff
I think a note should be added here to clarify that setting the load balancer schema to internal type should be set only when pointing Nebari to private subnets

# Ensure the subnet IDs are also set below
service.beta.kubernetes.io/aws-load-balancer-subnets: "subnet-0123456789abcdef,subnet-abcdef0123456789"
```

- **Use existing SSL certificate**
Instructs Nebari to use the SSL certificate specified by `[k8s-custom-secret-name]`

```
certificate:
type: existing
secret_name: [k8s-custom-secret-name]
```
4 changes: 3 additions & 1 deletion docs/docs/references/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
/>
</div>

Nitty-gritty technical descriptions of how Nebari works.
Technical descriptions of how Nebari works.

- [Enhanced Security](enhanced-security.md) - Nebari security configuration guide
- [Local Container Repo](container-sources.md) - Deploying Nebari from a Local Container Repo
<DocCardList items={useCurrentSidebarCategory().items}/>
3 changes: 1 addition & 2 deletions docs/nebari-slurm/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,7 @@ _Note_: All slurm related configuration needs to be passed down as a string.
### Services
Additional services can be added to the `jupyterhub_services`
variable. Currently this is only `<service-name>:
<service-apikey>`. You must keep the `dask_gateway` section.
variable. Currently this is only `<service-name>: <service-apikey>`. You must keep the `dask_gateway` section.

```yaml
jupyterhub_services:
Expand Down
Loading