Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow creation of deploy keys #16

Closed
zeidlos opened this issue Jan 27, 2025 · 10 comments
Closed

Allow creation of deploy keys #16

zeidlos opened this issue Jan 27, 2025 · 10 comments
Labels
enhancement New feature or request go Pull requests that update Go code good first issue Good for newcomers

Comments

@zeidlos
Copy link

zeidlos commented Jan 27, 2025

I am currently trying to bootstrap a new kubernetes cluster, using terraform.
Within this process I also want to install fluxcd onto the cluster.
Fluxcd is allowing for a helm deployment.

What do I need?

In order for flux to reconcile the project, I need to give it ssh-keys, so it can pull from the repository.
I want to be able to create a new ssh-keypair from within terraform and then, using the forgejo-provider, upload the deploy key onto the repository with read/write permissions.

If you want a beta-tester for this, please hit me up.
Sadly I believe to lack the necessary skills to create this feature within this provider myself. :)

@stdevel stdevel added enhancement New feature or request good first issue Good for newcomers go Pull requests that update Go code labels Jan 28, 2025
@stdevel
Copy link
Collaborator

stdevel commented Jan 28, 2025

That's an interesting idea! Sounds like it would be required to implement a Terraform provisioner. Looks like the Forgejo API offers a call for this:

Image

What do you think, @acch?

@acch
Copy link
Member

acch commented Jan 28, 2025

Thanks @zeidlos for bringing up this idea! Makes a ton of sense, and I guess it would provide value to many users...

I've briefly checked the forgejo-sdk. Looks like this is the function we would need to use:

... which requires these options (link):

type CreateKeyOption struct {
	// Title of the key to add
	Title string `json:"title"`
	// An armored SSH key to add
	Key string `json:"key"`
	// Describe if the key has only read access or read/write
	ReadOnly bool `json:"read_only"`
}

Hence, looks totally doable!

@acch
Copy link
Member

acch commented Feb 2, 2025

@zeidlos @stdevel I've started working on this. Just to make sure I'm addressing the correct use case: you're looking to deploy something like the following configuration, correct?

# Private key
resource "tls_private_key" "ed25519" {
  algorithm = "ED25519"
}

# Personal repository
resource "forgejo_repository" "personal" {
  name = "personal_test_repo"
}

# Deploy key
resource "forgejo_deploy_key" "this" {
  repository_id = forgejo_repository.personal.id
  key           = trimspace(tls_private_key.ed25519.public_key_openssh)
  title         = "test_key"
  read_only     = false
}

Let me know if that's correct. I'll need to get some unit tests in order, but should be able to provide something worth testing in the next couple of days...

@zeidlos
Copy link
Author

zeidlos commented Feb 3, 2025

This looks great!

Please take a look at: https://registry.terraform.io/providers/fluxcd/flux/latest/docs
There you'll see examples for github and gitlab. Forgejo could be in there as well. :)

@zeidlos
Copy link
Author

zeidlos commented Feb 3, 2025

For now I'm deploying flux via helm chart using a predefined key that i've uploaded manually to forgejo. This works as well and is not too much overhead, but it would be nicer if the key-handling could be done via terraform. This also would help with key-rotation.

@acch
Copy link
Member

acch commented Feb 9, 2025

@zeidlos @stdevel I've uploaded a new release v0.2.0 to the Terraform / OpenTofu registries - you can get it from there. The new version now supports a forgejo_deploy_key resource. Here's an example in the docs. Please let me know if it addresses your specific use case, or what's missing.

Two things to keep in mind:

  • Reading through the Flux Provider docs, it appears to me that Flux requires a repo that has already been initialized. Hence, you'll probably want to set forgejo_repository.auto_init to true (see docs).
  • Also note that you'll need to remove trailing \n characters from the key. tls_private_key adds a trailing \n, but Forgejo API will remove it... hence, you'll need to trim the forgejo_deploy_key.key string, e.g. using trimspace() (see docs).

Once you're able successfully deploy a Forgejo configuration for Flux, it would be totally rockstar awsome if you could supply your working example code. I would love to submit a PR to the Flux provider to add the Forgejo example (alongside GitHub, GitLab, and Helm) - what do you think?

@zeidlos
Copy link
Author

zeidlos commented Feb 10, 2025

Will test today and give you an example!

@zeidlos
Copy link
Author

zeidlos commented Feb 11, 2025

@acch @stdevel it works perfectly!

Okay, the premise I am working with is:

I already have a flux repository that is in use by multiple clusters (homelab, local testing, dev, stage, prod, etc) and I want to bootstrap another cluster or recreate one of the existing ones.

This Terraform file also uses the Hetznercloud Terraform provider to provide a fully working cluster, but I'll omit certain parts for brevity.

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    hcloud = {
      source  = "hetznercloud/hcloud"
      version = ">= 1.49.1"
    }
   flux = {
      source  = "fluxcd/flux"
      version = ">= 1.2"
    }
    tls = {
      source = "hashicorp/tls"
    }
    forgejo = {
      source = "svalabs/forgejo"
    }
  }
}


module "kube-hetzner" {
# Hetznercloud config lives here. :)
}

# Not sure I actually need this
provider "kubernetes" {
  host                   = module.kube-hetzner.kubeconfig_data.host
  client_certificate     = module.kube-hetzner.kubeconfig_data.client_certificate
  client_key             = module.kube-hetzner.kubeconfig_data.client_key
  cluster_ca_certificate = module.kube-hetzner.kubeconfig_data.cluster_ca_certificate
}

provider "flux" {
  kubernetes = {
    host                   = module.kube-hetzner.kubeconfig_data.host
    client_certificate     = module.kube-hetzner.kubeconfig_data.client_certificate
    client_key             = module.kube-hetzner.kubeconfig_data.client_key
    cluster_ca_certificate = module.kube-hetzner.kubeconfig_data.cluster_ca_certificate
  }
  git = {
    # TODO: We're better off using the data.forgejo_repository information here than hardcoding.
    url = "ssh://git@redacted/org/repo.git"
    ssh = {
      username    = "git"
      private_key = tls_private_key.ed25519.private_key_openssh
    }
  }
}

# Make sure to set FORGEJO_API_TOKEN in your environment
provider "forgejo" {
  host = "https://redacted.dev"
}

# create ssh_keypair to use as a deploy key in order to give flux
# access to the repository
resource "tls_private_key" "ed25519" {
  algorithm = "ED25519"
}

# reference existing repository
# alternatively you can use the forgejo_repository resource to create
# a new repository. (https://registry.terraform.io/providers/svalabs/forgejo/latest/docs/resources/repository)
data "forgejo_repository" "my_repo" {
  owner = {
    login = "org"
  }
  name = "repo"
}

# upload created ssh key as a deploy key to existing repository
resource "forgejo_deploy_key" "this" {
  repository_id = data.forgejo_repository.my_repo.id
  key           = trimspace(tls_private_key.ed25519.public_key_openssh)
  title         = "deploy_key"
  read_only     = false
}

# Create the flux_system namespace in order to bootstrap flux on the cluster
resource "kubernetes_namespace" "flux_system" {
  depends_on = [module.kube-hetzner]
  metadata {
    annotations = {
      name = "flux-system"
    }

    labels = {
      mylabel = "flux-system"
    }

    name = "flux-system"
  }
}

# Create a kubernetes secret with the ssh keys so flux can use this to pull 
# the configuration from the forgejo repository
resource "kubernetes_secret" "ssh_keypair" {
  metadata {
    name      = "flux-system"
    namespace = "flux-system"
  }

  type = "Opaque"

  data = {
    "identity.pub" = trimspace(tls_private_key.ed25519.public_key_openssh)
    "identity"     = trimspace(tls_private_key.ed25519.private_key_openssh)
    "known_hosts"  = "redacted"
  }

  depends_on = [kubernetes_namespace.flux_system]
}

# finally bootstrap flux with the git command
resource "flux_bootstrap_git" "this" {
  depends_on              = [tls_private_key.ed25519]
  disable_secret_creation = true
  embedded_manifests      = true
  path                    = "flux/clusters/hetzner"
}

Using this, I successfully create a Hetznercloud Kubernetes cluster, create a Forgejo deploy key into my pre-existing repository and initialize fluxcd on that cluster. Takes about 5-10 Minutes until everything is up and all flux resources are reconciled and up and running (obviously depending on the contents of your flux repository).

If you want, I can provide you with the full, unredacted file in private. It's still WIP. Also I'll create one to spin up a local kind cluster, I can share in the future if needed.

@acch
Copy link
Member

acch commented Feb 15, 2025

@zeidlos Great - thanks a million!

I'll prepare a PR to the Flux Provider documentation, and let you review it...

Are you good with closing this issue for the time being?

@zeidlos
Copy link
Author

zeidlos commented Feb 18, 2025

Yes, of course! Ticket scope has been fulfilled. :)
Again, thank you very much for your help!

I'm still exploring forgejo, but it looks great so far!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request go Pull requests that update Go code good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

3 participants