> ## Documentation Index
> Fetch the complete documentation index at: https://docs.skyhook.io/llms.txt
> Use this file to discover all available pages before exploring further.

# GitHub Actions setup

> Give Skyhook's generated GitHub Actions workflows the credentials they need to build images and deploy to your clusters

Skyhook generates GitHub Actions workflows that build your images and deploy to your clusters. Those workflows need two things from you:

1. **A way to authenticate to your cloud provider** — so they can push to your container registry and talk to your cluster's Kubernetes API
2. **A way to write back to your Git repos** — semver bumps on release, GitOps overlay updates, commits against a separate deployment repo

This page covers both. For what the workflows do and which actions they call, see [CI/CD Configuration](/application/cicd/configuration). For the secret/variable names as a cheat-sheet, see [Secrets and variables reference](/application/cicd/configuration#secrets-and-variables-reference).

## Three GitHub integrations, three purposes

If you run through full onboarding you'll set up as many as three separate GitHub integrations. They do different things — don't install one and assume it covers the others:

| Integration               | What it does                                                                                                                                     | When you need it                                                           | Set up with                                                                                                                                                            |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **GitHub Actions OIDC**   | Lets your CI/CD workflows authenticate to AWS, GCP, or Azure without long-lived keys.                                                            | Every project that uses the generated workflows with a cloud provider.     | [`skyhook github setup`](/cli-reference/skyhook_github_setup)                                                                                                          |
| **Deployment GitHub App** | Lets workflows push commits to a **separate deployment repo** (GitOps overlays, image-tag bumps). Issues short-lived App tokens, not user creds. | Only if your Kubernetes manifests live in a different repo from your code. | [`skyhook onboard deploy-auth`](/cli-reference/skyhook_onboard_deploy-auth)                                                                                            |
| **ArgoCD GitHub App**     | Lets **ArgoCD** read your GitOps repo from inside the cluster. Completely separate from the one above.                                           | Only if you're using GitOps with ArgoCD.                                   | [`skyhook onboard argocd configure-access`](/cli-reference/skyhook_onboard_argocd_configure-access) — covered in [GitOps with ArgoCD](/infrastructure/gitops/overview) |

Most teams using GitOps end up with all three. Most teams doing direct kubectl deploys from a single repo only need the first.

## Cloud authentication

The recommended path for AWS and GCP is OIDC — GitHub Actions authenticates to your cloud provider with a short-lived token, no long-lived keys to rotate. The Skyhook CLI can set this up end-to-end.

<Tabs>
  <Tab title="CLI (recommended)">
    [`skyhook github setup`](/cli-reference/skyhook_github_setup) creates the cloud-side trust relationship — the OIDC identity provider and an IAM role on AWS, or a Workload Identity Federation pool and service account on GCP — and prints the GitHub repository variables you need to add.

    ```bash theme={"system"}
    skyhook github setup
    ```

    Useful flags:

    * `--cloud gcp` / `--cloud aws` — skip the cloud prompt
    * `--github-org <org>` — explicit GitHub org (auto-detected from git remote otherwise)
    * `--template-only` — print CloudFormation/Terraform instead of running cloud CLI commands, useful when you don't have `aws`/`gcloud` locally or want the setup applied by a platform team
    * `--dry-run` — show what would change without touching anything

    The command expects `gh` plus the relevant cloud CLI (`gcloud` or `aws`) to be installed and authenticated. If they're not, it falls back to template mode.

    On success you'll see the variables to add to **GitHub → Settings → Secrets and variables → Actions → Variables**:

    * AWS: `AWS_BUILD_ROLE`, `AWS_DEPLOY_ROLE`
    * GCP: `WIF_PROVIDER`, `WIF_SERVICE_ACCOUNT`

    You can re-run the command any time — it detects existing configuration and offers to update or reuse it.

    <Tip>
      For the full OIDC flow — detection of existing setups, scope-mismatch handling, multi-account setups, template/dry-run modes, and the manual walkthroughs (GCP + AWS) using the same resource names the CLI creates — see [GitHub OIDC setup](/infrastructure/cicd-setup/github-oidc).
    </Tip>
  </Tab>

  <Tab title="GCP manual (service account key)">
    Use this path if you can't or don't want to set up Workload Identity — for example, on restricted projects where you don't have IAM admin.

    1. Set the right project:

       ```bash theme={"system"}
       gcloud config set project <project>
       ```

    2. Create a service account and grant it the permissions the workflows need (GKE access + Artifact Registry write):

       ```bash theme={"system"}
       SA_NAME="github-actions"
       PROJECT="$(gcloud config get-value project)"
       SA_EMAIL="${SA_NAME}@${PROJECT}.iam.gserviceaccount.com"

       gcloud iam service-accounts create "$SA_NAME" \
         --display-name="GitHub Actions deploy"

       for role in roles/container.developer roles/artifactregistry.writer; do
         gcloud projects add-iam-policy-binding "$PROJECT" \
           --member="serviceAccount:$SA_EMAIL" --role="$role"
       done
       ```

    3. Generate a JSON key and download it:

       ```bash theme={"system"}
       gcloud iam service-accounts keys create sa-key.json \
         --iam-account="$SA_EMAIL"
       ```

    4. Add the `sa-key.json` contents as a GitHub secret named `GCP_CREDENTIALS`:
       * Organization secret for org-wide access
       * Repository secret for single-repo access

    The generated build and deploy workflows fall back to `GCP_CREDENTIALS` when the WIF variables aren't set.

    <Warning>
      Service account keys are long-lived credentials. Prefer Workload Identity Federation when you can — [`skyhook github setup`](/cli-reference/skyhook_github_setup) is the fastest path.
    </Warning>
  </Tab>

  <Tab title="AWS manual (access keys)">
    Use this path if your environment can't support OIDC — for example, self-hosted GitHub Actions runners behind a firewall.

    Create a deploy user with the permissions the workflows need, generate an access key, and set it as GitHub secrets `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`:

    ```bash theme={"system"}
    AWS_REGION="us-east-1"
    IAM_USER_NAME="github-actions"

    aws iam create-user --user-name $IAM_USER_NAME

    # ECR (build) + EKS read access (deploy)
    aws iam attach-user-policy --user-name $IAM_USER_NAME \
      --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess

    aws iam put-user-policy --user-name $IAM_USER_NAME \
      --policy-name EKSSkyhookAccessV1 \
      --policy-document '{
        "Version": "2012-10-17",
        "Statement": [{
          "Action": ["eks:AccessKubernetesApi", "eks:Describe*", "eks:List*"],
          "Effect": "Allow",
          "Resource": "*"
        }]
      }'

    aws iam create-access-key --user-name $IAM_USER_NAME
    ```

    Copy the `AccessKeyId` and `SecretAccessKey` from the output into GitHub secrets.

    If you're using EKS with the legacy `aws-auth` ConfigMap (rather than EKS access entries), map the IAM user in:

    ```bash theme={"system"}
    kubectl edit configmap aws-auth -n kube-system
    ```

    ```yaml theme={"system"}
    data:
      mapUsers: |
        - userarn: arn:aws:iam::<account-id>:user/github-actions
          username: github-actions
          groups:
            - system:masters  # scope this down for production
    ```

    Modern EKS clusters use [access entries](https://docs.aws.amazon.com/eks/latest/userguide/access-entries.html) instead — if your cluster was created after late 2023, prefer those over `aws-auth` edits.
  </Tab>

  <Tab title="Azure">
    Create a service principal (Azure AD application) and grant it the roles the workflows need — **AcrPush** on your ACR and **Azure Kubernetes Service Cluster User Role** on your AKS cluster.

    Two credential paths:

    **OIDC with federated credentials (recommended).** No long-lived client secret — Azure AD trusts GitHub OIDC tokens directly. Configure a federated credential on the app registration with the GitHub subject pattern `repo:<ORG>/<REPO>:ref:refs/heads/main` (or `:pull_request`, `:environment:<name>`, etc. depending on when workflows should be allowed to assume it). Then add these as GitHub repository **variables** (not secrets):

    * `AZURE_CLIENT_ID` — the app registration's application (client) ID
    * `AZURE_TENANT_ID` — your Azure AD tenant ID
    * `AZURE_SUBSCRIPTION_ID` — the subscription the AKS cluster lives in

    **Client secret.** If federated credentials don't work in your environment (e.g. self-hosted runners with no OIDC issuer), create a client secret and store all three as GitHub **secrets**:

    * `AZURE_CLIENT_ID`
    * `AZURE_CLIENT_SECRET`
    * `AZURE_TENANT_ID`

    Prefer the OIDC path — client secrets are long-lived and need rotation.
  </Tab>

  <Tab title="BYOK / other registries">
    For clusters you operate yourself and non-cloud registries (Docker Hub, GHCR, Harbor, Quay, or any OCI-compliant registry), the workflows use standard Kubernetes and Docker authentication.

    **Cluster access:**

    * Create a `KUBECONFIG` secret in GitHub with the base64-encoded contents of a kubeconfig scoped to your deployment namespace. Prefer a dedicated ServiceAccount with namespace-scoped RBAC over a cluster-admin credential.

    **Registry credentials:**

    * **GitHub Container Registry** — workflows use `github.token` automatically, no secret needed
    * **Docker Hub** — `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` secrets
    * **Private / OCI-compliant** — `REGISTRY_USERNAME` and `REGISTRY_PASSWORD` secrets

    **Image pull inside the cluster:**

    If your registry requires authentication to pull, create an `imagePullSecret` in each namespace:

    ```bash theme={"system"}
    kubectl create secret docker-registry regcred \
      --docker-server=<your-registry-url> \
      --docker-username=<username> \
      --docker-password=<password> \
      -n <namespace>
    ```

    <Info>
      No cloud provider CLI or IAM configuration is needed for BYOK. Kubernetes auth + Docker registry credentials are sufficient.
    </Info>
  </Tab>
</Tabs>

## Writing back to your repos

The workflows push commits back to Git for a few reasons: bumping a service's `VERSION` file on release, writing new image tags into GitOps overlays, and (for services with a separate deployment repository) updating manifests in a repo other than the source repo. Each of those needs something more privileged than the default `GITHUB_TOKEN`.

### Separate deployment repositories

If your Kubernetes manifests live in a different repo from your code, workflows need cross-repo access. Skyhook's **Deployment GitHub App** is the recommended way — fine-grained permissions, auto-rotating tokens, and attribution under a bot identity instead of a user.

<Tabs>
  <Tab title="CLI (recommended)">
    ```bash theme={"system"}
    skyhook onboard deploy-auth
    ```

    [`skyhook onboard deploy-auth`](/cli-reference/skyhook_onboard_deploy-auth) walks through creating the GitHub App, installing it on the deployment repo, and storing the credentials where the workflows can find them. Supports re-running for reconfiguration.

    On success you'll have `GH_APP_ID` and `GH_APP_PK` as GitHub secrets (organization-wide or per-repo, depending on your GitHub plan).
  </Tab>

  <Tab title="UI">
    Open **Settings → Code & Repositories → GitHub App**, then **Install App**. See [GitOps → Deployment GitHub App](/infrastructure/gitops/overview#deployment-github-app) for the full walkthrough.
  </Tab>

  <Tab title="Personal Access Token">
    Quick fallback — tied to one user's GitHub identity.

    1. Create a [fine-grained PAT](https://github.com/settings/tokens?type=beta) with Contents: Read & Write on the deployment repo (and code repo if you need semver bumps).
    2. Add it as a GitHub secret named `GHA_PAT` (repository or organization scope).

    The workflows fall back to `GHA_PAT` when the GitHub App credentials aren't set.
  </Tab>
</Tabs>

### Protected branches

If your default branch is protected with required reviews, the workflow can't push `VERSION` bumps or GitOps overlay updates with the built-in `GITHUB_TOKEN` — GitHub [doesn't grant it bypass permissions](https://github.com/orgs/community/discussions/13836).

The simplest fix is to use the `GH_APP_ID`/`GH_APP_PK` secrets from the Deployment GitHub App (recommended above) and allow that app to bypass branch protection under **Repository settings → Branches → Branch protection rules → Allow specified actors to bypass required pull requests**.

As a fallback, you can use a PAT from a user with bypass permissions (organization admin, repository admin, or an explicit bypass actor):

1. Create a PAT at [https://github.com/settings/tokens](https://github.com/settings/tokens) with full `repo` access.
2. Add it as an org or repo secret named `GHA_PAT`.
3. Reference it in the checkout step of `release.yml` and (for GitOps) `deploy.yml`:

   ```yaml theme={"system"}
   - uses: actions/checkout@v6
     with:
       token: ${{ secrets.GHA_PAT }}
   ```

The generated workflows reference `GHA_PAT` automatically when it's set, so step 3 isn't needed if you're on the current template.

## Verify the setup

Once credentials are in place, trigger a run to confirm. From the service directory, use [`skyhook deploy`](/cli-reference/skyhook_deploy) to build and deploy to a safe environment:

```bash theme={"system"}
skyhook deploy --env dev --build -y
```

Or push a commit to your default branch and watch the **Release** workflow run in GitHub Actions. If it fails on authentication, the [CI/CD troubleshooting guide](/application/cicd/troubleshooting#authentication-issues) maps the common error messages back to the specific secret or variable that's missing or misconfigured.
