Setup
What your team does to bring up a Lunar Dedicated install, covering connectivity, the depositor account, your Git platform credential, and the secret deposit.
Earthly provisions and operates your entire install. This page is everything your side does, in order, with the reasoning behind each step.
Read the Overview first if you want the model, the security posture, and what the service includes. This page is the hands-on companion.
Your steps at a glance
Steps 2 and 3 are quick and independent. Step 1 is the one that determines your timeline. It involves a DNS change and an AWS domain-ownership check on your side, so start it the day you send your answers even though it's needed last.
Earthly builds the install in parallel. The only early input it needs from you is your depositor account ID (step 2).
First, the questionnaire
Your answers to the onboarding questionnaire parameterize the install: region, hub access, internal targets, DNS, sizing, maintenance windows, contacts. Send them to Earthly whenever they're settled; nothing waits on a meeting.
Earthly replies with your coordinates packet: tenant name, region, dedicated account ID, deposit role ARN, deposit ExternalId, and your webhook URL. Several steps below need values from it.
Step 1 — Private connectivity, if Lunar needs it
Your install reaches outwards as well as inwards. The Hub calls your Git platform to read repositories, register webhooks, and post results; collectors, catalogers, and policies run inside your install and reach the systems they gather data from, such as registries, ticketing, and internal APIs. If any of those targets isn't reachable from the public internet, Lunar needs a private path to it.
This includes your Git platform itself. A self-managed GitHub Enterprise Server or GitLab instance that only resolves inside your network is one of these targets, and an easy one to overlook: the Hub needs the private path before any collector does.
Start here if that applies to you: PrivateLink to Your Internal Systems.
That page is self-contained and written for your networking team. It covers publishing your internal service as an AWS PrivateLink endpoint service, allowlisting Earthly's dedicated account, and associating a verified DNS name so Lunar reaches your service by its real hostname with working TLS.
This can take time. The AWS work is straightforward, but it includes publishing a DNS record and waiting for AWS to verify domain ownership, which means a DNS change on your side (and potentially your change-management process). If DNS changes queue behind a change window, that wait alone can add days. Start this in parallel first, even though it isn't needed until the end.
Not sure it applies? The Do you need this? questions at the top of that page take two minutes and can rule the work out entirely: public targets need nothing, and an internet-facing target can often just allowlist the install's single outbound IP.
Step 2 — Identify your depositor account
During setup, your secrets (your Git platform credential, the encryption key, and the webhook secret) are written directly into your dedicated account's secret store, never through Earthly's systems. They're deposited by assuming a write-only deposit role in the dedicated account. Earthly creates that role while provisioning your account, with your depositor principal baked into its trust policy. The trust policy is fixed at that point, which is why your account ID is the one input Earthly needs early.
Send Earthly the 12-digit ID of the AWS account you will deposit from. Earthly trusts that account principal (arn:aws:iam::<YOUR_ACCOUNT_ID>:root) plus a deposit-specific ExternalId (included in your coordinates packet).
That does not grant everyone in the account access; your IAM administrator still chooses which role or user may call sts:AssumeRole. Attach this caller-side policy to the role, user, or permission set your team will use:
The exact deposit-role ARN for the Resource line is also in your coordinates packet. It's fine to prepare the policy with a placeholder and tighten it when the packet arrives.
Notes that save a support round-trip:
Trusting the account's
:rootARN is not logging in as the AWS root user. The root user cannot assume roles; use a normal IAM or SSO principal.Earthly does not trust a specific SSO-generated role ARN, so recreating a permission set does not silently break the deposit trust. Your caller-side policy remains the gate.
If an SCP or permission boundary blocks cross-account
sts:AssumeRole, your AWS administrator must allow this one deposit-role ARN.
No AWS account? Tell Earthly along with your questionnaire answers. When you're ready to deposit, Earthly will mint one-hour temporary credentials for the write-only deposit role and deliver them over a secure channel.
Step 3 — Set up your Git platform
Lunar authenticates to your Git platform with a credential that you create, on the groups, orgs, and repos it should monitor. Earthly never holds org-admin access, and never handles the credential itself.
Git Platforms covers what differs between the two platforms. The Hub-configuration sections of those pages are for self-hosted installs only, since Earthly configures the Hub for you.
Create a GitHub App and install it on your org.
Use the hosted setup tool, or create it by hand on GitHub Enterprise Server, or if your security review needs every permission spelled out first. The permissions it is granted are listed for that review.
Set the webhook URL from your coordinates packet (
https://hub.<TENANT>.<your-dedicated-domain>/webhooks/github). It's fine that the install isn't live yet.Download the App's private key (
.pem). It's deposited in step 4; it never goes to Earthly, in any channel.Leave the App's "Webhook secret" field empty. Lunar registers and secures its own repository webhooks from inside your install; the App-level webhook carries no traffic.
Send Earthly: the App ID, the installation ID, and the org(s) it's installed on. Those are identifiers, not secrets.
Create a group access token on each top-level group Lunar should monitor.
Go to the top-level group, then Settings → Access tokens → Add new token. Give it the
apiscope and theMaintainerorOwnerrole.Pick an expiry and set a calendar reminder for it now. GitLab tokens expire on a fixed date, with no overlap period. See Rotations and changes.
Copy the token when GitLab shows it; it is displayed once. It's deposited in step 4 and never goes to Earthly.
There is no webhook URL to set, and no webhook secret to paste back. Lunar registers a webhook on each project itself and generates the signing secret inside your install, so unlike GitHub there's nothing to configure on the GitLab side.
Send Earthly: the top-level group path each token covers, plus your instance hostname if you're self-managed. Those are identifiers, not secrets.
Self-managed instances must be declared. Lunar decides whether a host is GitLab from configuration, so if you don't tell Earthly your instance hostname it will be treated as GitHub and every operation against it fails in confusing ways. gitlab.com needs no declaration.
Step 4 — Deposit your secrets
Run this from a terminal once you have your coordinates packet and your Git platform credential. Expect about 30 minutes end to end. You'll need the tenant name, region, deposit role ARN, and deposit ExternalId from the packet. Earthly is glad to join a call if you need help.
The deposit ExternalId unlocks only the write-only deposit role. It is not Earthly's deploy ExternalId, and it grants nothing else.
Use an AWS profile for a principal carrying the caller-side policy from step 2:
Write the token to a file first, so it never lands in your shell history:
Repeat once per top-level group. Lunar keys tokens by group, so each group's token is deposited separately under its own group path.
Your instance hostname is not part of the deposit — it's configuration, not a secret. Earthly applies it from the identifiers you sent in step 3.
If Earthly issued one-hour temporary credentials instead (the no-AWS-account path), export the three values in your shell and drop the last two flags; the credentials already are the deposit role:
What the command does:
Generates the encryption key and webhook secret inside this flow and deposits them write-once. Neither is ever printed — the install consumes them directly.
Deposits the Git platform credential you supplied: the GitHub App PEM, or the GitLab group access token.
Verifies each write from the write response. The deposit role is write-only by design: it cannot read the secrets back, and the setup flow never returns them to Earthly.
Leaves nothing to paste back on either platform: Lunar registers repository and project webhooks itself and manages their signing secrets inside your install.
If you get AccessDenied, in order of likelihood:
Your caller doesn't have
sts:AssumeRoleon the deposit-role ARN.Deposit ExternalId typo; it must match the packet exactly.
An SCP or permission boundary in your org blocks
sts:AssumeRoleto accounts outside your organization. Loop in whoever owns your SCPs.On the no-AWS-account path: the one-hour credentials expired. Ask Earthly to mint a fresh set; it takes seconds.
Go live
Earthly completes the install, verifies it end-to-end, and hands you the hub access token and your Grafana login over a secure channel. Treat the token like a root credential.
Then, on your side:
Load your workload secrets: the API keys your catalogers, collectors, and policies need. These go straight to your hub via the CLI, never through Earthly's systems:
Finish DNS, if you delegated a subdomain. Add the NS records Earthly provides to hand off the zone. Earthly then manages every record and the TLS certificate under it.
Complete your hub-access step, if you chose PrivateLink. Create the inbound endpoint and coordinate with Earthly, usually via your networking team. Over the internet there's nothing to do.
Confirm private connectivity, if you set it up in step 1. Earthly runs a verification pass from a real Lunar workload (hostname resolution, TLS with hostname verification, an authenticated application request) and only points your install at the internal hostname once all of it passes.
Rotations and changes
GitHub App PEM. Re-run step 4 with the new file. The encryption key and webhook secret will not rotate, but the PEM will.
GitLab group access token. GitLab tokens carry a fixed expiry, and there is no overlap period where old and new both work, so replacing one is a cutover rather than a rollover. Create the replacement in GitLab, re-run step 4 with it ahead of the expiry date, then revoke the old one. See expiry and rotation.
If a GitLab token lapses, Lunar stops posting results and stops reacting to webhooks for that group. Because the token is read at startup, nothing fails loudly to tell you. Set the calendar reminder when you create the token, not later.
If you used the AWS-less fallback, contact Earthly before any credential rotation; fresh one-hour credentials are minted for the re-run and nothing else changes.
Adding or removing an internal target. Publish the new endpoint service following PrivateLink to Your Internal Systems and send Earthly the same six values. Earthly makes a small, reviewed change on its side, with no downtime for your install.
Last updated
