Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
3b4b106
fix(helm): publish every chart version instead of replacing the Pages…
tim-thacker-nullify Sep 14, 2026
46c8b0c
ci(helm): dry-run the repository build on pull requests
tim-thacker-nullify Sep 14, 2026
498006a
fix(helm): check the index against tags and keep charts independent w…
tim-thacker-nullify Sep 14, 2026
ca0ec3d
ci(helm): release only from main, retry tagging, pin actions and gate…
tim-thacker-nullify Sep 14, 2026
f2ed96e
fix(helm): verify recovered chart assets, tag before deploying and ga…
tim-thacker-nullify Sep 14, 2026
3cb53fa
fix(helm): restore tagged-but-unpublished chart versions automatically
tim-thacker-nullify Sep 14, 2026
6d4738d
fix(helm): warn instead of failing on a tag with no release asset
tim-thacker-nullify Sep 15, 2026
4ebc754
fix(helm): verify hand-made tags before deploy and use a REST-only re…
tim-thacker-nullify Sep 15, 2026
b136bd4
fix(helm): verify hand-made tags before every release attach, not jus…
tim-thacker-nullify Sep 15, 2026
c310521
fix(helm): gate hand-made-tag verification to attach paths only
tim-thacker-nullify Sep 15, 2026
41e78ca
Merge pull request #65 from Nullify-Platform/fix/helm-publish-review
tim-thacker-nullify Sep 15, 2026
b928748
Merge pull request #70 from Nullify-Platform/fix/helm-publish-review-r2
tim-thacker-nullify Sep 15, 2026
1bb74ce
Merge pull request #75 from Nullify-Platform/fix/helm-publish-review-r3
tim-thacker-nullify Sep 15, 2026
0efc700
Merge pull request #84 from Nullify-Platform/fix/helm-publish-review-r4
tim-thacker-nullify Sep 15, 2026
65fb481
Merge pull request #95 from Nullify-Platform/fix/helm-publish-review-r5
tim-thacker-nullify Sep 15, 2026
aa9539f
Merge pull request #96 from Nullify-Platform/fix/helm-publish-review-r6
tim-thacker-nullify Sep 15, 2026
e2e17bf
Merge pull request #97 from Nullify-Platform/fix/helm-publish-review-r7
tim-thacker-nullify Sep 15, 2026
0c22648
feat(helm): add nullify-k8s-readonly-access chart for managed EKS sca…
tim-thacker-nullify Sep 17, 2026
05123e8
merge: resolve conflicts with main
tim-thacker-nullify Sep 17, 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
21 changes: 20 additions & 1 deletion .github/workflows/helm-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
- "manifests/**"
- "scripts/publish-helm-repo.sh"
- "scripts/test-helm-charts.sh"
- "scripts/check-rbac-manifest.sh"
- "tests/helm/**"
- ".github/workflows/helm-release.yml"
push:
Expand All @@ -16,6 +17,7 @@ on:
- "manifests/**"
- "scripts/publish-helm-repo.sh"
- "scripts/test-helm-charts.sh"
- "scripts/check-rbac-manifest.sh"
- "tests/helm/**"
- ".github/workflows/helm-release.yml"
workflow_dispatch:
Expand Down Expand Up @@ -109,10 +111,27 @@ jobs:
echo "Charts a merge to main would skip:"
cat skipped.txt

# PR signal only. Packaging the readonly-access chart already runs
# helm-charts/nullify-k8s-readonly-access/ci/pre-publish.sh (the same script).
# Do not put this on release.needs: a drift here must skip that chart, not
# block publishing every other chart.
rbac-manifest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1
with:
version: ${{ env.HELM_VERSION }}

- name: Raw manifest matches the chart's default render
run: scripts/check-rbac-manifest.sh

release:
needs: [charts, validate]
# Runs even when a chart's validate leg fails: the publish script re-runs
# each chart's tests and skips only the failing chart.
# each chart's tests and that chart's ci/pre-publish.sh hook, and skips
# only the failing chart.
if: >-
!cancelled()
&& github.event_name != 'pull_request'
Expand Down
87 changes: 77 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ This repository provides comprehensive infrastructure-as-code templates for inte
| Method | Best For | Prerequisites |
|--------|----------|---------------|
| **🎯 Helm Charts** | Kubernetes-native teams, GitOps workflows | EKS or GKE cluster, Helm 3.x, kubectl |
| **Managed EKS scan (no agent)** | EKS clusters with a public API endpoint; nothing runs in the cluster | AWS integration deployed, EKS access entry, kubectl (Helm optional) |
| **🏗️ CloudFormation** | AWS-centric infrastructure, ClickOps teams | AWS CLI, appropriate IAM permissions |
| **🔧 Terraform (AWS)** | Infrastructure-as-code, multi-cluster teams | Terraform, AWS provider configured |
| **☁️ Terraform (GCP)** | GCP environments, Workload Identity Federation | Terraform, `gcloud` auth on the host project, org or folder admin access |
Expand Down Expand Up @@ -149,6 +150,67 @@ kubectl get jobs -n nullify
kubectl logs -l job-name=<job-name> -n nullify
```

## **Managed EKS scan (no in-cluster agent)**

Nullify can read an EKS cluster's configuration from Nullify's AWS account through the cluster's public API endpoint, using the read-only integration role. Nothing runs in the cluster; you grant list-only RBAC to a group and map the integration role to that group with an EKS access entry.

- RBAC: the [`nullify-k8s-readonly-access`](helm-charts/nullify-k8s-readonly-access/README.md) chart, or the equivalent raw manifest [`manifests/nullify-readonly-rbac.yaml`](manifests/nullify-readonly-rbac.yaml) for kubectl and Flux.
- Default: ClusterRole `nullify-readonly` with `list` on 27 kinds and `get` on `/version`, bound to group `nullify-readonly`.
- Secrets are listed as a Table (name, type, key count, age). The scanner does not receive Secret values or key names. `grantSecretsRead` / `grantConfigMapsRead` must match `collectSecrets` / `collectConfigMaps` on the cluster in Nullify.
- Do not use `AmazonEKSViewPolicy` (the scan fails); `AmazonEKSAdminViewPolicy` works but is far broader. See the chart README before choosing it.

| | In-cluster collector | Managed EKS scan |
|---|---|---|
| Where it runs | CronJob in your cluster | Nullify's AWS account |
| Network | Outbound from the cluster to AWS S3/STS | Inbound to the EKS public endpoint from Nullify egress IPs |
| Private-only endpoint | Supported | Not supported |
| In-cluster objects | ServiceAccount, ClusterRole, ClusterRoleBinding, CronJob | ClusterRole, ClusterRoleBinding |
| A denied kind | Skipped | Whole cluster scan fails |
| Platforms | EKS, GKE | EKS |

### Map the Nullify role to the group

```bash
export CLUSTER=my-cluster REGION=eu-west-1 ACCOUNT_ID=123456789012 CUSTOMER_NAME=acme
export ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/AWSIntegration-${CUSTOMER_NAME}-NullifyReadOnlyRole"
export NULLIFY_GROUP=nullify-readonly

aws eks describe-cluster --name "$CLUSTER" --region "$REGION" \
--query 'cluster.accessConfig.authenticationMode' --output text

aws eks create-access-entry --cluster-name "$CLUSTER" --region "$REGION" \
--principal-arn "$ROLE_ARN" --type STANDARD --kubernetes-groups "$NULLIFY_GROUP"
```

- Do **not** associate an EKS access policy. The chart's RBAC is the only grant.
- `update-access-entry --kubernetes-groups` **replaces** the group list. If the role already has an entry, include its existing groups.
- If the authentication mode is `CONFIG_MAP`, either switch to `API_AND_CONFIG_MAP` (one-way) or add the role to `aws-auth` `mapRoles` with `groups: [nullify-readonly]`.

Then install the chart (Helm, Flux, or kubectl) as described in the
[readonly-access chart README](helm-charts/nullify-k8s-readonly-access/README.md).

### Allow Nullify on the API endpoint

Add Nullify's egress IP addresses for your Nullify region to the cluster's
public access CIDRs. The region is where your Nullify tenant runs, not where the
cluster runs.

Fetch the current NAT addresses from `GET https://api.<tenant>.nullify.ai/dast/sourceips`.
That endpoint resolves live IPs per region and is the list to allow.

`ap-southeast-2` currently publishes `13.55.32.104/32`, `3.105.146.106/32`,
`13.211.99.100/32`. Confirm those against the API before you apply them, and do
the same for every other region — this repository does not pin those addresses.

`publicAccessCidrs` **replaces** the list, so merge with the current value, and
the list holds at most 40 CIDRs. If the current value is `0.0.0.0/0`, the
endpoint is already open to Nullify.

```bash
aws eks describe-cluster --name "$CLUSTER" --region "$REGION" \
--query 'cluster.resourcesVpcConfig.{public:endpointPublicAccess,cidrs:publicAccessCidrs}'
```

## 🏗️ **CloudFormation Deployment**

Deploy AWS infrastructure using CloudFormation templates for cross-account access and IAM role setup.
Expand Down Expand Up @@ -263,16 +325,20 @@ nullify-cloud-connector/
│ └── test-helm-charts.sh # Lint and render one chart (used by CI)
│
├── ⚙️ helm-charts/ # 🎯 KUBERNETES DEPLOYMENT
│ └── nullify-k8s-collector/ # Main Helm chart for K8s collector
│ ├── Chart.yaml # Chart metadata and version
│ ├── values.yaml # Default values (generic/safe)
│ ├── values-example.yaml # Example production configuration
│ ├── README.md # Chart-specific documentation
│ └── templates/ # Kubernetes resource templates
│ ├── serviceaccount.yaml # IRSA service account
│ ├── clusterrole.yaml # Read-only cluster permissions
│ ├── clusterrolebinding.yaml # RBAC binding
│ └── cronjob.yaml # Main collector CronJob
│ ├── nullify-k8s-collector/ # Main Helm chart for K8s collector
│ │ ├── Chart.yaml # Chart metadata and version
│ │ ├── values.yaml # Default values (generic/safe)
│ │ ├── values-example.yaml # Example production configuration
│ │ ├── README.md # Chart-specific documentation
│ │ └── templates/ # Kubernetes resource templates
│ │ ├── serviceaccount.yaml # IRSA service account
│ │ ├── clusterrole.yaml # Read-only cluster permissions
│ │ ├── clusterrolebinding.yaml # RBAC binding
│ │ └── cronjob.yaml # Main collector CronJob
│ └── nullify-k8s-readonly-access/ # List-only RBAC for the managed EKS scan
│
├── manifests/
│ └── nullify-readonly-rbac.yaml # Raw manifest equal to the readonly chart's default render
│
├── aws-integration-setup/ # 🏗️ AWS INFRASTRUCTURE
│ ├── 🏗️ cloudformation/ # CloudFormation Templates
Expand Down Expand Up @@ -436,6 +502,7 @@ no remaining merge-order hold for #60 / #65 / #70 / #75.
|----------|-------------|
| [IMPLEMENTATION.md](IMPLEMENTATION.md) | Implementation details and technical overview |
| [Chart README](helm-charts/nullify-k8s-collector/README.md) | Helm chart documentation (EKS + GKE) |
| [Read-only access chart README](helm-charts/nullify-k8s-readonly-access/README.md) | Managed EKS scan: RBAC install (Helm, Flux, kubectl) and verification |
| [CloudFormation README](aws-integration-setup/cloudformation/README.md) | CloudFormation template documentation |
| [AWS Terraform README](aws-integration-setup/terraform/README.md) | AWS Terraform modules documentation |
| [GCP Terraform README](gcp-integration-setup/terraform/README.md) | GCP Terraform modules documentation |
Expand Down
1 change: 1 addition & 0 deletions helm-charts/nullify-k8s-readonly-access/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ci/
14 changes: 14 additions & 0 deletions helm-charts/nullify-k8s-readonly-access/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v2
name: nullify-k8s-readonly-access
description: Read-only Kubernetes RBAC that lets Nullify's managed EKS scan list cluster configuration. Installs no workload.
type: application
version: 0.1.0
kubeVersion: ">=1.21.0-0"
maintainers:
- name: Nullify
url: https://nullify.ai
keywords:
- security
- kubernetes
- rbac
- eks
Loading
Loading