Before you start
A-Packets is a self-hosted PCAP analysis platform for network forensics and incident response: it reconstructs HTTP sessions, DNS activity, credentials and transferred files from packet captures. Deployed to your cluster, every capture is analysed and stored inside your own infrastructure. See A-Packets On-Premise for deployment options, licensing and what the analysis produces.
This guide installs the connected Pro or Enterprise Helm package into an existing Kubernetes cluster. It uses local email-and-password authentication for the first administrator. The chart deploys five application components: API, uploader, receiver, worker and web. You provide PostgreSQL, NATS and S3-compatible object storage separately.
| Requirement | Prepare |
|---|---|
| Cluster access | A Kubernetes cluster and kubectl credentials authorized to create the namespace, Deployments, Services, ConfigMaps, Secrets, ServiceAccount and Ingress. Capacity for the replica and resource settings in your delivered customer-values.yaml. |
| Administrator tools | Helm 3.13 or newer, Bash, OpenSSL, Cosign compatible with the delivered Sigstore bundle (example release verified with 3.1.3), sha256sum, tar, curl and jq. |
| External services | PostgreSQL, NATS and S3-compatible storage reachable from application pods. Create the S3 bucket and grant the application access before installation. Arrange persistence, backups and access controls for these services. |
| Delivery and license | The Helm archive, checksum, signature bundle, public key, pull-only registry credentials and a separately supplied active license with deployment_helm and auth_local. |
| Network | Every cluster node must be able to pull images from registry.apackets.com. Pods need access to your external services and, if enabled, SMTP. |
| DNS and HTTPS | An ingress controller, its IngressClass, a DNS name pointing at the controller, and a TLS certificate trusted by your users' browsers. TLS terminates at the ingress controller. |
Examples use https://apackets.acme.example, [email protected], release name apackets and namespace apackets. Replace the example addresses with domains you control. Replace every value in angle brackets before running a command or applying configuration. Run the shell examples in Bash.
Check the destination cluster before making changes:
kubectl config current-context
kubectl get nodes -o wide
helm version --short
If cluster nodes cannot reach the A-Packets registry, use the Enterprise offline package and follow the air-gapped installation guide.
1. Verify the release
Download these four files from your delivery message into one directory. Keep the signed download links private and keep the separately supplied license.jwt in a location accessible only to the deployment administrator.
apackets-cosign.pub
apackets-pro-helm-VERSION.tar.gz
apackets-pro-helm-VERSION.tar.gz.sha256
apackets-pro-helm-VERSION.tar.gz.sha256.sigstore.json
Set the version from the delivery filename; for example, 0.0.1-rc.19. For an Enterprise package, change apackets-pro-helm to apackets-enterprise-helm. Keep these variables in the same Bash session throughout the guide.
APACKETS_RELEASE='<version>'
APACKETS_PACKAGE='apackets-pro-helm'
APACKETS_ARCHIVE="${APACKETS_PACKAGE}-${APACKETS_RELEASE}.tar.gz"
Check the public key
Open the A-Packets signing key page independently of the delivery links. Compute the SHA-256 fingerprint of the DER-encoded key you downloaded:
openssl pkey -pubin -in apackets-cosign.pub -outform DER \
| openssl dgst -sha256
Compare the complete result with the live page's SHA-256 (DER) value. Do not use sha256sum apackets-cosign.pub: that hashes the PEM file, not the DER-encoded key.
Where to find the published fingerprint
Check the signature and archive
After the fingerprint matches, authenticate the checksum file, then verify the archive:
cosign verify-blob \
--insecure-ignore-tlog \
--key apackets-cosign.pub \
--bundle "${APACKETS_ARCHIVE}.sha256.sigstore.json" \
"${APACKETS_ARCHIVE}.sha256"
Expected result: Verified OK. This delivery uses a release-key signature that is not published to a public transparency log. --insecure-ignore-tlog skips the transparency-log check; it still verifies the signature with the key you checked. Cosign also prints a warning about the skipped log check.
sha256sum --check "${APACKETS_ARCHIVE}.sha256"
Expected result: the archive filename followed by OK.
2. Extract the package
tar -xzf "${APACKETS_ARCHIVE}"
cd "${APACKETS_PACKAGE}-${APACKETS_RELEASE}"
umask 077
chmod 600 ./config/customer-values.yaml
Run the remaining Helm commands from this directory. It contains apackets-VERSION.tgz, config/release-values.yaml, config/customer-values.yaml, authentication examples under config/auth/, an optional SMTP example, and INSTALL.md.
Edit the customer values and copied overlays. Do not edit values.yaml inside the chart. Keep release-values.yaml from this package: it pins the delivered image version. Do not set global.imageTag in customer values.
3. Configure registry access
Create the application namespace, then create its pull Secret using the pull-only username and token from your delivery. A docker login on your workstation does not give Kubernetes nodes access to the registry.
kubectl create namespace apackets --dry-run=client -o yaml \
| kubectl apply -f -
These Bash prompts keep the literal token out of shell history. Run them on a trusted administrator workstation; kubectl receives the token as a process argument.
read -r -p 'Registry username: ' APACKETS_REGISTRY_USER
read -r -s -p 'Registry token: ' APACKETS_REGISTRY_TOKEN
printf '\n'
kubectl create secret docker-registry apackets-registry \
--namespace apackets \
--docker-server=registry.apackets.com \
--docker-username="$APACKETS_REGISTRY_USER" \
--docker-password="$APACKETS_REGISTRY_TOKEN"
unset APACKETS_REGISTRY_TOKEN APACKETS_REGISTRY_USER
If your platform team already manages a registry pull Secret in this namespace, use its name in global.imagePullSecrets instead. A Secret in another namespace cannot be referenced here.
4. Configure the application and HTTPS
Edit the matching sections of config/customer-values.yaml. Merge the values below into its existing keys, and retain the supplied replica and resource settings unless you have sized a different deployment.
global:
imageRegistry: registry.apackets.com/apackets
imagePullSecrets:
- name: apackets-registry
config:
domain: https://apackets.acme.example
secureCookies: true
databaseUrl: 'postgres://<DB_USER>:<URL_ENCODED_DB_PASSWORD>@postgres.acme.example:5432/apackets'
natsUrl: nats://nats.acme.example:4222
s3Endpoint: https://s3.acme.example
s3Region: '<S3_REGION>'
s3Bucket: apackets
secrets:
s3AccessKey: '<S3_ACCESS_KEY>'
s3SecretKey: '<S3_SECRET_KEY>'
encryptionKey: '<64_HEX_CHARACTERS>'
service:
web:
type: ClusterIP
ingress:
enabled: true
className: '<INGRESS_CLASS>'
host: apackets.acme.example
tlsSecretName: apackets-tls
Use endpoints reachable from the pods, including Kubernetes Service DNS names where appropriate. Percent-encode special characters in the database password when building its URL. Use the authentication, transport security and certificate trust settings required by your infrastructure. The chart does not create PostgreSQL, NATS, object storage or the bucket.
Generate and preserve the encryption key
openssl rand -hex 32
Copy the output into secrets.encryptionKey. It must contain exactly 64 hexadecimal characters (32 bytes). Keep a protected backup: the application uses this key to encrypt values in PostgreSQL. Reuse the same key on every upgrade. Generating a replacement is not a supported way to rotate it or recover access.
Keep customer values, overlays and license files out of source control and shared logs. Helm stores supplied values in release records. In this chart, databaseUrl and natsUrl are rendered into a ConfigMap, including any embedded credentials; restrict access to ConfigMaps and Helm release records as well as Secrets.
Prepare ingress and TLS
Choose an existing ingress class and point your deployment's DNS record at its controller:
kubectl get ingressclass
Arrange a TLS Secret named apackets-tls in the application namespace. Your certificate manager can create it, or you can create it from an existing certificate and private key:
kubectl create secret tls apackets-tls \
--namespace apackets \
--cert=/path/to/fullchain.pem \
--key=/path/to/privkey.pem
The certificate must cover your actual deployment hostname. Match config.domain to the HTTPS URL and ingress.host to its hostname. Set secureCookies: true explicitly; the delivered customer template defaults to false. Configure HTTPS redirection and upload-size/time limits on your controller to suit your capture files. See the Kubernetes ingress documentation and your controller's configuration guide.
5. Configure the first administrator
cp ./config/auth/local.values.yaml.example ./config/auth/local.values.yaml
chmod 600 ./config/auth/local.values.yaml
Set the first administrator's address in the copied file:
config:
adminEmail: [email protected]
One of the first web pods creates the local administrator and logs a temporary password once. Save that password immediately after installation, before any pod restart or upgrade. The first sign-in requires you to change it.
The license must be active and grant both deployment_helm and auth_local. Configure exactly one license source: the commands below use --set-file license.jwt=/path/to/license.jwt. Alternatively, set license.existingSecret to an existing Secret in this namespace and omit the --set-file argument from both lint and install. The Secret must contain the key specified by license.secretKey, which defaults to license.jwt.
Using another authentication provider
Choose a complete overlay from config/auth/ and replace the local overlay in each Helm command. Google, Microsoft and GitHub require auth_oauth; LDAP / Active Directory requires auth_ldap; SAML requires auth_saml.
With OAuth, the first successful user becomes the first administrator; restrict provider access before exposing sign-in. LDAP and SAML require a matching config.ldapAdmin* or config.samlAdmin* bootstrap selector in their overlay. Follow the supplied INSTALL.md and overlay comments for provider settings. A missing entitlement can hide a configured method from the sign-in page even while pods are Ready.
6. Set up outgoing email (optional)
SMTP is optional for the first local sign-in. Configure it if you need invitations and password-reset emails. To enable SMTP at startup, copy its overlay:
cp ./config/optional/smtp.values.yaml.example ./config/optional/smtp.values.yaml
chmod 600 ./config/optional/smtp.values.yaml
Replace its contents with the settings from your mail administrator:
smtp:
enabled: true
config:
smtpHost: smtp.acme.example
smtpPort: "587"
smtpSecurity: starttls
smtpFrom: [email protected]
secrets:
smtpLogin: '<SMTP_USER>'
smtpPassword: '<SMTP_PASSWORD>'
smtpSecurity accepts starttls, tls or none; use the port and security mode required by your provider. smtpFrom must be an email address only, without a display name. Set the login and password together, or leave both empty when your mail server does not require authentication.
Add the following argument to both Helm commands in the next step, after the authentication overlay and before the license argument:
--values ./config/optional/smtp.values.yaml
If email is not required, omit this overlay. The chart then omits SMTP bootstrap variables. After signing in, use Settings → E-mail to verify delivery and manage email settings.
7. Validate and install
Validate the chart using the same version, values, optional overlays and license that you will install. The Helm values order matters: release defaults first, customer configuration second, then the selected authentication and optional SMTP overlays. The final image tag pins all application images to the delivered version.
helm lint "./apackets-${APACKETS_RELEASE}.tgz" \
--values ./config/release-values.yaml \
--values ./config/customer-values.yaml \
--values ./config/auth/local.values.yaml \
--set-file license.jwt=/path/to/license.jwt \
--set-string global.imageTag="${APACKETS_RELEASE}"
Expected result: 1 chart(s) linted, 0 chart(s) failed. Lint checks chart configuration; it does not prove that credentials, external services or license entitlements work. Resolve all validation errors before installing. Rendered manifests and Helm dry-run output may contain secrets; do not paste them into shared tickets.
helm upgrade --install apackets "./apackets-${APACKETS_RELEASE}.tgz" \
--namespace apackets \
--create-namespace \
--values ./config/release-values.yaml \
--values ./config/customer-values.yaml \
--values ./config/auth/local.values.yaml \
--set-file license.jwt=/path/to/license.jwt \
--set-string global.imageTag="${APACKETS_RELEASE}" \
--wait \
--timeout 10m
Helm should report STATUS: deployed. Save the one-time administrator password next, before changing values or restarting pods.
8. Save the password and sign in
Read the initial web pods' logs in a private terminal. The chart can run multiple web replicas, so search all of them instead of assuming the newest pod created the administrator:
kubectl logs --namespace apackets \
--selector app.kubernetes.io/instance=apackets,app.kubernetes.io/component=web \
--all-containers=true --prefix --tail=-1 \
| grep -F 'Generated temporary local admin password'
The matching log entry contains the temporary administrator password (the temporary_password field in structured logs). Store it in your organization's password manager. Do not include it in screenshots or support messages.
Open https://apackets.acme.example/signin using your own hostname. Confirm the certificate is trusted, sign in with the configured administrator email and temporary password, and set a new password when prompted.
9. Verify the installation
Check the release and all five application Deployments. The resource names below assume the release name apackets and no chart name overrides:
helm status apackets --namespace apackets -o json \
| jq -e '.info.status == "deployed"'
for component in api uploader receiver worker web; do
kubectl get deployment "apackets-apackets-${component}" \
--namespace apackets -o json \
| jq -e '.spec.replicas > 0 and .status.availableReplicas == .spec.replicas'
done
Each check should return true. Check that the API, uploader and web Services have ready endpoints:
for service in apackets-apackets-api apackets-apackets-uploader apackets-apackets-web; do
kubectl get endpointslice --namespace apackets \
--selector "kubernetes.io/service-name=${service}" -o json \
| jq -e '[.items[].endpoints[]? | select(.conditions.ready != false)] | length > 0'
done
Check HTTPS from a client that can resolve the deployment hostname. Do not disable certificate verification:
curl -sS -o /dev/null -w '%{http_code}\n' https://apackets.acme.example/readyz
curl -sS -o /dev/null -w '%{http_code}\n' https://apackets.acme.example/healthz
curl -sS -o /dev/null -w '%{http_code}\n' https://apackets.acme.example/
curl -sS -o /dev/null -w '%{redirect_url}\n' https://apackets.acme.example/
curl -sS -o /dev/null -w '%{http_code}\n' https://apackets.acme.example/signin
Expected: 200 for both health endpoints and sign-in, and an unauthenticated root redirect to https://apackets.acme.example/signin (303 in the example release). Also confirm the email field, password field and Sign in button are visible in the browser. A 200 page without a usable authentication method is not a successful installation.
Check license startup messages from every uploader, receiver and worker replica:
for component in uploader receiver worker; do
kubectl logs --namespace apackets \
--selector "app.kubernetes.io/instance=apackets,app.kubernetes.io/component=${component}" \
--all-containers=true --prefix --tail=-1 \
| grep -Ei 'license is active|read-only mode|entitlement'
done
Expect an active-license message from each pod. Resolve read-only or entitlement warnings even if the Deployments are Ready. Finally, sign in and analyze a small, sanitized capture to confirm the upload and processing path works.
Updates and Secret rotation
Before upgrading, back up the application data and encryption key, read the delivered release notes, and verify the new package using the same fingerprint, signature and checksum procedure. Extract it into a new directory, then bring forward your customer values and selected overlays. Use the new package's release-values.yaml and chart; set APACKETS_RELEASE to its version.
Keep the release name, namespace and encryption key unchanged. Repeat the lint and helm upgrade --install commands above with the same overlay order, including SMTP if enabled, then repeat the availability and sign-in checks. Do not assume a Helm rollback also reverses database changes.
Externally managed Secrets
By default the chart manages the application and license Secrets. Changes to their rendered contents or the ConfigMap change pod-template checksums and trigger an application rollout.
To use your own application Secret, set secrets.existingSecret to its name in the release namespace. It must provide the environment-variable keys expected by the chart: S3_ACCESS_KEY, S3_SECRET_KEY, ENCRYPTION_KEY, and any credentials required by your enabled providers, such as SMTP_LOGIN and SMTP_PASSWD. Use the delivered chart's Secret template as the full key reference. Helm cannot validate the externally stored encryption key.
Helm cannot detect content changes in secrets.existingSecret or license.existingSecret. After updating one of these Secrets, change rollout.restartAt in customer values to a new timestamp and run the normal upgrade command:
rollout:
restartAt: "2026-09-21T12:00:00Z"
Use a different value for each restart. This restarts pods to load the updated credentials or license; it does not make replacing the application's encryption key safe.
Data and backups
The Helm chart relies on your external PostgreSQL database and S3 bucket. Include both in your backup and restore procedures, together with the encryption key, license, customer configuration and provider credentials. Follow your infrastructure's recovery requirements for NATS as well. Test restoration in an isolated environment before relying on it.
Keep the encryption key with the corresponding database backup. Application pod availability alone does not demonstrate durable storage or a working restore procedure.
Troubleshooting
| Symptom | Check |
|---|---|
| Fingerprint, signature or checksum mismatch | Stop. Confirm the files belong to the same delivery and compare against the live signing key page. Contact support with sanitized verification output. |
ImagePullBackOff / ErrImagePull | Inspect pod events with kubectl describe pod POD_NAME -n apackets. Check the registry path, release tag, node connectivity and CA trust, and that the pull-only Secret exists in this namespace and is referenced by global.imagePullSecrets. |
| Helm times out / pods are not Ready | Inspect pod events and affected service logs. Check cluster capacity, DNS, network policies, PostgreSQL and NATS access, and S3 endpoint, credentials and pre-created bucket. Lint cannot validate these connections. |
| HTTPS fails or sign-in does not persist | Check DNS, IngressClass, controller events, certificate hostname and TLS Secret. Keep domain, ingress.host and HTTPS cookie settings consistent. Use kubectl describe ingress apackets-apackets -n apackets. |
| Missing license / read-only mode | Configure exactly one license source. Check the Secret key, license validity and expiry, and deployment_helm entitlement. Update the license and roll out the application. |
| Selected sign-in method is hidden | Check that the complete auth overlay was included and its matching auth_local, auth_oauth, auth_ldap or auth_saml entitlement is active. |
Invalid SMTP bootstrap configuration | Supply the complete enabled SMTP overlay or omit it. Use an address-only sender and either both login and password or neither. Check the overlay was included in lint and install. |
| No temporary password in logs | Search all initial web replicas. If the account already exists, startup does not issue a new password. If the original pod logs are gone, use configured email recovery or ask your A-Packets contact. |
| External credentials changed but pods did not restart | Update rollout.restartAt and upgrade. Externally managed Secret contents do not participate in Helm's rendered checksums. |
Contact support
Raise the issue with your A-Packets contact. Include the package version, Kubernetes and Helm versions, release name, namespace, failing step, and sanitized status or error output. Remove delivery URLs, database credentials, registry tokens, license contents, encryption keys and temporary passwords before sharing files or logs.