Add cluster-side connect operations to the ArgoCD skill
Fold the operational half of ArgoCD work into this skill, which until now covered only authoring the Copier-templated repo. The two never overlapped: authoring edits files in git, connecting applies objects to a cluster. - Add references/connecting-a-repo.md: host-key trust, repository Secret registration with its project-scoping decision table, bootstrap apply ordering, SSO RBAC, prerequisites, and verification commands. - Add references/connect-env-vars.md: layered .env loading, variable table, CLI flags, and SSH deploy-key rules. - Add SKILL.md section 11 plus scope-routing rows, and state the split: sections 1-10 author, section 11 operates. - Map the numbered cluster/0000-bootstrap layout onto the cluster/argocd layout, since the connect scripts reference those folder names directly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
# Connecting a Repository to ArgoCD
|
||||
|
||||
Cluster-side operations that make an **already-rendered** GitOps repo reachable by an
|
||||
**already-installed** ArgoCD: trusting the git host key, registering the repository Secret,
|
||||
applying the app-of-apps bootstrap, and granting SSO users read access.
|
||||
|
||||
Read this when onboarding a repo to a cluster for the first time, rotating or scoping the
|
||||
repository credential, or debugging a connect run — kube context, namespaces, repo
|
||||
credentials, bootstrap paths. Every other reference in this skill concerns *authoring* the
|
||||
repo; this one concerns *operating* ArgoCD against it.
|
||||
|
||||
Driven by the wrapper-first `.scripts/argo-cd/` shell module (`Taskfile -> api -> lib`; see
|
||||
the `development-scripts` skill for that architecture). Variables and CLI flags:
|
||||
`references/connect-env-vars.md`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Operations
|
||||
|
||||
| Operation | Task | Purpose |
|
||||
|---|---|---|
|
||||
| Trust the git repo SSH host key | `task argo-cd:0000-trust-repo-host` | run once per git host, before connect |
|
||||
| Onboard / connect a repo | `task argo-cd:0100-connect-one` | preflight → repo Secret → bootstrap apply |
|
||||
| Let SSO users view apps (RBAC) | `task argo-cd:0200-grant-sso-readonly` | ArgoCD install config, not repo state |
|
||||
|
||||
The numbered task names encode run order. The module is expandable — sync, app management,
|
||||
UI, and uninstall operations belong here as they are built.
|
||||
|
||||
## 2. Trust the repo host (run once, before connect)
|
||||
|
||||
For SSH repos, ArgoCD's repo-server verifies the git server's host key against
|
||||
`argocd-ssh-known-hosts-cm`. A self-hosted host is not there by default, so `connect-one`
|
||||
fails with:
|
||||
|
||||
```text
|
||||
ssh: handshake failed: knownhosts: key is unknown
|
||||
```
|
||||
|
||||
```bash
|
||||
task argo-cd:0000-trust-repo-host # parses host+port from the repo URL
|
||||
```
|
||||
|
||||
`lib/-trust-repo-host.sh` parses host and port from the repo URL, `ssh-keyscan`s it,
|
||||
**appends** to `argocd-ssh-known-hosts-cm` — never overwriting the shipped defaults — and
|
||||
restarts `argocd-repo-server` so the mounted ConfigMap reloads. Idempotent: it skips when the
|
||||
host is already present.
|
||||
|
||||
A ConfigMap patch alone can take ~60s to remount. The restart makes it deterministic.
|
||||
|
||||
## 3. Onboard / connect
|
||||
|
||||
```bash
|
||||
task argo-cd:0000-trust-repo-host # once per host
|
||||
task argo-cd:0100-connect-one # reads the .env layers; override with --repo-url=… etc.
|
||||
```
|
||||
|
||||
Entry chain: `api/connect-one.sh` → `lib/--index.sh` (base loader → argo-cd reader → api
|
||||
index) → `_argocd_connect_one`:
|
||||
|
||||
```text
|
||||
require KUBE_CONFIG_PATH KUBE_CONFIG_CONTEXT ARGOCD_NAMESPACE ARGOCD_TARGET_DIR ARGOCD_GIT_REPO_URL
|
||||
export KUBECONFIG=<kube config path>
|
||||
preflight → repo-register → bootstrap-apply
|
||||
```
|
||||
|
||||
### Step 1 — preflight
|
||||
|
||||
- `command -v kubectl`
|
||||
- `kubectl --context <ctx> get namespace <ns>` — ArgoCD reachable
|
||||
- the bootstrap directory exists in the target repo — the render must already have run
|
||||
|
||||
### Step 2 — repo-register
|
||||
|
||||
Builds a `kubectl create secret generic`, pipes it to `kubectl apply -f -`, then labels it
|
||||
`argocd.argoproj.io/secret-type=repository`:
|
||||
|
||||
```text
|
||||
--from-literal=type=git
|
||||
--from-literal=url=<repo url> # SSH form: git@host:owner/repo.git
|
||||
[--from-literal=project=<appproject>] # when set → project-scoped
|
||||
[--from-file=sshPrivateKey=<key path>] # when set
|
||||
```
|
||||
|
||||
| ssh key | project | Result |
|
||||
|---|---|---|
|
||||
| none | none | skip Secret (public, global repo) |
|
||||
| none | set | create Secret (type + url + project) — project-scoped public repo |
|
||||
| set | any | create Secret with `sshPrivateKey` |
|
||||
| set, file missing | any | fail fast |
|
||||
|
||||
The matching **public** key must be a read-only deploy key on the repository.
|
||||
|
||||
### Step 3 — bootstrap-apply
|
||||
|
||||
Applies the bootstrap manifests in filename order — the AppProject (`0000-*`) before the
|
||||
app-of-apps (`0100-*`). ArgoCD then reconciles everything else **from Git**.
|
||||
|
||||
The app-of-apps source must set `directory.recurse: true`, because feature Applications live
|
||||
in nested subdirectories. Without it only the top-level manifest is read and children never
|
||||
appear.
|
||||
|
||||
## 4. Project-scoped repositories
|
||||
|
||||
Setting an AppProject name makes the repo a **project-scoped repository**: the Secret carries
|
||||
a `project` field, so only Applications in that AppProject may use it.
|
||||
|
||||
- The SSH key is optional (public repo); if a key path is set, the file must exist.
|
||||
- The Secret is skipped **only** when there is neither a key nor a project scope.
|
||||
- A public repo **with** a project scope still gets a Secret — type, url, project, no key.
|
||||
|
||||
The AppProject's `sourceRepos` must permit the repo URL, and the app-of-apps `spec.project`
|
||||
must match.
|
||||
|
||||
## 5. Let SSO users view apps (RBAC)
|
||||
|
||||
With an empty `argocd-rbac-cm` `policy.default`, non-admin SSO/OIDC users see an **empty**
|
||||
Applications list. `admin` bypasses RBAC, so the apps exist but are invisible to SSO logins —
|
||||
which reads as "my apps disappeared" rather than as a permissions problem.
|
||||
|
||||
```bash
|
||||
task argo-cd:0200-grant-sso-readonly # sets policy.default (default role:readonly)
|
||||
```
|
||||
|
||||
Idempotent; argocd-server reloads live, no restart needed.
|
||||
|
||||
This is ArgoCD **install** configuration living on the cluster — not part of the GitOps repo,
|
||||
so it is neither rendered by Copier nor reconciled from Git.
|
||||
|
||||
`role:readonly` grants **all** authenticated users read access to **all** applications. Scope
|
||||
a role to a specific SSO group when you need tighter control.
|
||||
|
||||
## 6. Prerequisites the scripts do NOT handle
|
||||
|
||||
- **ArgoCD must already be installed.** Preflight only *checks* that the namespace exists.
|
||||
- **The rendered repo must be pushed.** bootstrap-apply applies local manifests, but those
|
||||
manifests point ArgoCD at a `repoURL` + `path` **in Git**. Unpushed → the app-of-apps
|
||||
cannot find its path.
|
||||
- **The public deploy key must be on the repo**, read-only, for SSH auth to work.
|
||||
- **A successful render must exist first** — the target's bootstrap directory has to be on
|
||||
disk. See `references/environments.md` for rendering an environment.
|
||||
- `kubectl` reachable at the configured kubeconfig and context.
|
||||
|
||||
## 7. Bootstrap paths — two repository shapes
|
||||
|
||||
The connect scripts reference the rendered repo's cluster folders by name, so those names are
|
||||
a contract between the template and the scripts. Two shapes are in use:
|
||||
|
||||
| Purpose | `cluster/argocd/` shape (SKILL.md) | numbered shape |
|
||||
|---|---|---|
|
||||
| Bootstrap — AppProject + app-of-apps | root app applies it | `cluster/0000-bootstrap` |
|
||||
| Child Application manifests | `cluster/argocd/<NNN-name>/` | `cluster/0300-applications` |
|
||||
| Helm values / resources | `cluster/resources/<NNN-name>/` | `cluster/0500-resources` |
|
||||
|
||||
The authoring rules in `SKILL.md` describe the first shape. Whichever a repo uses, preflight
|
||||
and bootstrap-apply must point at its **real** bootstrap directory — if the template renames
|
||||
cluster folders, update both step scripts in the same change.
|
||||
|
||||
The deployed surface is only the manifests under paths an ArgoCD Application actually
|
||||
references.
|
||||
|
||||
## 8. Verify without a cluster
|
||||
|
||||
Render the repository Secret client-side to confirm project scoping before applying:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic <secret-name> \
|
||||
--from-literal=type=git --from-literal=url=<repo-url> \
|
||||
--from-literal=project=<appproject> \
|
||||
--from-file=sshPrivateKey=<key-path> \
|
||||
--dry-run=client -o yaml # decode data.project → must equal the AppProject name
|
||||
```
|
||||
|
||||
## 9. Post-onboard checks
|
||||
|
||||
```bash
|
||||
kubectl -n <ns> get appproject <project>
|
||||
kubectl -n <ns> get applications
|
||||
kubectl -n <ns> get secret <repo-secret> -o jsonpath='{.data.project}' | base64 -d
|
||||
argocd app list # if the argocd CLI is available
|
||||
```
|
||||
|
||||
## 10. Anti-patterns
|
||||
|
||||
- Committing the SSH private key instead of keeping it a local file referenced by path.
|
||||
- Letting `.env*` values reach the deployed `cluster/**` manifests — they are tooling inputs.
|
||||
- Adding a `:default` task wrapper; the env layers already supply values. Keep one env-driven
|
||||
task and override with flags after `--`.
|
||||
- Hardcoding cluster folder names in step scripts without keeping them in sync with the
|
||||
template (§7).
|
||||
- Keeping two connect modules. If a duplicate exists, prefer the wired one and delete the
|
||||
other.
|
||||
Reference in New Issue
Block a user