Skip to content

hckops/actions

Repository files navigation

actions

For a working example see kube-template

kube-do-action

test-kube-do

Manages DigitalOcean Kubernetes cluster lifecycle

Creates or deletes clusters based on a config definition

# examples/kube-test-do-lon1.yaml
version: 1
name: test-do-lon1
provider: digitalocean
+ status: UP
- status: DOWN

digitalocean:
  cluster:
    count: 1
    region: lon1
    size: s-1vcpu-2gb

Example

- name: Provision
  uses: hckops/actions/kube-do-action@main
  with:
    access-token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
    config-path: examples/kube-test-do-lon1.yaml
    wait: true

Requires DIGITALOCEAN_ACCESS_TOKEN secret

How to test it locally

# build image
docker build -t hckops/kube-do-action ./kube-do-action

# run action
docker run --rm \
  -e GITHUB_REPOSITORY="INVALID_GITHUB_REPOSITORY" \
  -e GITHUB_OUTPUT="INVALID_GITHUB_OUTPUT" \
  -v ${PWD}/examples:/examples \
  hckops/kube-do-action \
    "INVALID_GITHUB_TOKEN" \
    "INVALID_ACCESS_TOKEN" \
    "./examples/kube-test-do-lon1.yaml" \
    "main" \
    "true" \
    "false" \
    "false"

TODOs

bootstrap-action

test-bootstrap

Bootstraps a platform with ArgoCD

Example

- name: Bootstrap
  uses: hckops/actions/bootstrap-action@main
  with:
    argocd-admin-password: ${{ secrets.ARGOCD_ADMIN_PASSWORD }}
    argocd-git-ssh-key: ${{ secrets.ARGOCD_GIT_SSH_KEY }}
    kubeconfig: <REPOSITORY_NAME>-kubeconfig.yaml
    chart-path: ./charts/argocd-config

Requires

  • ARGOCD_ADMIN_PASSWORD secret
    docker run --rm -it python:3-alpine ash
    pip3 install bcrypt
    
    # create secret with bcrypt hash
    python3 -c "import bcrypt; print(bcrypt.hashpw(b'<MY-PASSWORD>', bcrypt.gensalt()).decode())"
  • ARGOCD_GIT_SSH_KEY secret
    # generate ssh key pair
    ssh-keygen -t ed25519 -C "argocd@example.com" -N '' -f /tmp/id_ed25519_argocd
    
    # add public key to a github user account with access to the repo
    cat /tmp/id_ed25519_argocd.pub | xclip -selection clipboard
    
    # create secret with private key
    cat /tmp/id_ed25519_argocd | xclip -selection clipboard
    
    # cleanup
    rm /tmp/id_ed25519_argocd*

How to test it locally on minikube

# see "scripts/local.sh"
make bootstrap
# default cluster
make bootstrap kube="template"

# admin|argocd
kubectl port-forward svc/argocd-server -n argocd 8080:443

kube-secrets-action

test-kube-secrets

Initializes operator's master Secret

Supports

Example

# AKEYLESS
- name: Secrets
  uses: hckops/actions/kube-secrets-action@main
  with:
    kubeconfig: <REPOSITORY_NAME>-kubeconfig.yaml
    operator: external-secrets-akeyless
    external-secrets-akeyless-access-id: ${{ secrets.AKEYLESS_ACCESS_ID }}
    external-secrets-akeyless-access-type: api_key
    external-secrets-akeyless-access-type-param: ${{ secrets.AKEYLESS_ACCESS_KEY }}

# LASTPASS
- name: Secrets
  uses: hckops/actions/kube-secrets-action@main
  with:
    kubeconfig: <REPOSITORY_NAME>-kubeconfig.yaml
    operator: edgelevel-lastpass
    edgelevel-lastpass-username: ${{ secrets.LASTPASS_USERNAME }}
    edgelevel-lastpass-password: ${{ secrets.LASTPASS_PASSWORD }}

Requires

  • AKEYLESS_ACCESS_ID and AKEYLESS_ACCESS_KEY secrets for Akeyless
    • In Auth Methods, create new API Key e.g. kube-template-action
    • In Access Roles, create new Role e.g. template-role, Associate Auth Method to the api key previously created and Add Rule for Secrets & Keys
    # returns AKEYLESS_ACCESS_TOKEN
    curl --request POST \
      --url https://api.akeyless.io/auth \
      --header 'accept: application/json' \
      --header 'content-type: application/json' \
      --data '{"access-type": "access_key", "access-id": "<AKEYLESS_ACCESS_ID>", "access-key": "<AKEYLESS_ACCESS_KEY>"}'
    
    # verify access rules
    curl --request POST \
      --url https://api.akeyless.io/get-secret-value \
      --header 'accept: application/json' \
      --header 'content-type: application/json' \
      --data '{"names": ["/path/to/MY_SECRET"], "token": "<AKEYLESS_ACCESS_TOKEN>"}'
  • LASTPASS_USERNAME and LASTPASS_PASSWORD secrets for LastPass

helm-dependencies-action

test-helm-dependencies

Keeps Helm dependencies up to date

See also dependabot/dependabot-core#2237

Example

# workflow example
- name: Helm Dependencies
  uses: hckops/actions/helm-dependencies-action@main
  with:
    user-email: "<EMAIL>"
    user-name: "<USERNAME>"
    config-path: examples/dependencies.yaml
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# config example
dependencies:
  # it will fetch the latest dependency from https://artifacthub.io/packages/helm/argo/argo-cd
  # and create a pr with the updated version using jq/yq path in Chart.yaml
  - name: "Argo CD"
    source:
      file: examples/test-chart/Chart.yaml
      path: .dependencies[0].version
    repository: 
      type: artifacthub
      name: argo/argo-cd

For more example see

How to test it locally, sample output

# build image
docker build -t hckops/helm-dependencies-action ./helm-dependencies-action

# dry run without creating a pr
docker run --rm \
  --env GITHUB_TOKEN=INVALID_TOKEN \
  --env GITHUB_REPOSITORY=INVALID_REPOSITORY \
  --env GITHUB_SHA=INVALID_SHA \
  --volume ${PWD}/examples:/examples \
  hckops/helm-dependencies-action \
    "examples/dependencies.yaml" \
    "INVALID_EMAIL" \
    "INVALID_USERNAME" \
    "main" \
    "true"

Recommendations

  • Automatically delete branches, see https://github.com/<OWNER>/<REPOSITORY>/settings

settings-delete-pr

  • Suggest to update branches, see https://github.com/<OWNER>/<REPOSITORY>/settings

settings-update-pr

  • Favour squashed PRs to keep a clean commit history, see https://github.com/<OWNER>/<REPOSITORY>/settings

settings-squash-pr

  • Enable default branch protection, see https://github.com/<OWNER>/<REPOSITORY>/settings/branches. The action pushes a status check named action/helm-dependencies upon success

settings-branch

Troubleshooting

  • If you get the following error, pull request create failed: GraphQL: GitHub Actions is not permitted to create or approve pull requests (createPullRequest)
    • make sure you've enabled Allow GitHub Actions to create and approve pull requests in your organization and repository settings
    • https://github.com/organizations/<ORGANIZATION>/settings/actions
    • https://github.com/<OWNER>/<REPOSITORY>/settings/actions

settings-create-pr

helm-lint-action

test-helm-lint

Validates Helm charts

Example

- name: Helm Lint
  uses: hckops/actions/helm-lint-action@main

TODOs

discord-action

test-discord

Interacts with Discord API

Example of Create message

- name: Notification
  uses: hckops/actions/discord-action@main
  with:
    action: create-message
    webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
    message: "Hello World"

Requires DISCORD_WEBHOOK_URL secret

How to test it locally

DISCORD_WEBHOOK_URL="INVALID_URL"
make discord-create webhook=${DISCORD_WEBHOOK_URL} message=test

docker build -t hckops/discord-action ./discord-action
docker run --rm hckops/discord-action "create-message" ${DISCORD_WEBHOOK_URL} "docker"

docker-template-action

Builds and publishes Docker images

See composite actions, useful to build base images in combination with matrixes

- name: Docker CI
  uses: hckops/actions/docker-template-action@main
  with:
    DOCKER_CONTEXT: "./docker/<IMAGE_NAME>"
    # optional
    DOCKER_FILE: "Dockerfile"
    DOCKER_IMAGE_NAME: "<IMAGE_NAME>"
    DOCKER_REPOSITORY: "<REPOSITORY_NAME>"
    # optional, default is sha
    DOCKER_DEFAULT_TAG: "latest"
    SECRET_DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
    SECRET_DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
    # optional
    SECRET_DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}

Development

Docker images

docker-ci

Action's base images

# run command
docker run --rm hckops/kube-base /bin/bash -c <kubectl|helm>

# start temporary container
docker run --rm --name hck-tmp -it hckops/kube-<base|argo|aws|do>

How to publish docker images

# list latest tags
curl -sS "https://api.github.com/repos/hckops/actions/tags" | jq '.[].name'

# publish with action
git tag docker-X.Y.Z
git push origin --tags

# build and publish manually (old)
make docker-build
make docker-publish version=vX.Y.Z token=<ACCESS_TOKEN>
make docker-clean

Actions to update when a new docker tag is created

  • bootstrap-action
  • helm-dependencies-action
  • helm-lint-action
  • kube-do-action
  • kube-secrets-action
# bump all images
make update-version old="<OLD_VERSION>" new="<NEW_VERSION>"

minikube

# install 
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb
sudo dpkg -i minikube_latest_amd64.deb

# local cluster
minikube start --driver=docker --embed-certs
minikube delete --all

# verify status
kubectl get nodes