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

Support for oci:// scheme (Helm 3.5.0) #666

Closed
topikettunen opened this issue Jan 20, 2021 · 47 comments · Fixed by #837
Closed

Support for oci:// scheme (Helm 3.5.0) #666

topikettunen opened this issue Jan 20, 2021 · 47 comments · Fixed by #837
Labels

Comments

@topikettunen
Copy link

Description

Helm 3.5.0 now supports oci:// scheme for pulling dependencies from OCI registries. Can we upgrade to it?

Potential Terraform Configuration

resource "helm_release" "prometheus_operator" {
  name       = "prometheus-operator"
  chart      = "kube-prometheus-stack"
  version    = "12.11.3"
  repository = "oci://..."
  namespace  = "default"
}

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment
@topikettunen
Copy link
Author

Ah, the oci:// support was only implemented for helm pull, so I guess its no use for us yet, right?

@sherifabdlnaby
Copy link

Yes please, this is helpful for using Terraform with OCI registeries such as AWS ECR.

@aareet aareet added needs-investigation upstream-helm Issue is in Helm not the provider labels Feb 17, 2021
@aareet
Copy link
Member

aareet commented Feb 17, 2021

Investigate when doing the work for #677

@stpierre
Copy link

It looks like #677 has a PR up, but at a glance it doesn't look like this is addressed. Is it still on the roadmap?

@lawliet89
Copy link
Contributor

The PR to update Helm involves a lot of files getting update due to vendoring. I think it's better off to explore this in a separate PR once the dependency has been upgraded.

@wjam
Copy link

wjam commented Apr 8, 2021

Looking at the Helm code, it seems that the only thing to do - now that #709 has been merged - is to set the HELM_EXPERIMENTAL_OCI environment variable that should unlock the feature?
https://github.com/helm/helm/blob/v3.5.3/internal/resolver/resolver.go#L128

@lawliet89
Copy link
Contributor

@wjam Unfortunately it doesn't seem to work for me. Needs more work to manually pull the chart first.

@aggyomfg
Copy link

aggyomfg commented Apr 30, 2021

As i suggest problem is here helm/helm#6982
Helm can't helm install oci://... only helm pull can :(

upd: Here is my temp WA for this case:

locals {
  example_chart_name = "example-chart"
  example_charts_url        = "gitlab.example.com:4567/helm-charts/"
  example_chart_version    = "0.1.0"
}

resource "null_resource" "get_example_chart" {
  provisioner "local-exec" {
    interpreter = ["/bin/bash", "-c"]
    command     = <<-EOT
    echo "Getting chart from OCI"
    export HELM_EXPERIMENTAL_OCI=1
    helm registry login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    helm chart pull ${local.example_charts_url}${local.example_chart_name}:${local.example_chart_version}
    helm chart export ${local.example_charts_url}${local.example_chart_name}:${local.example_chart_version} --destination /tmp/
  EOT
  }
}

# To CHANGE values in bellow chart null_resource.get_example_chart must be executed
# so if u changing values - you have to change "echo" in command block to trigger it or use
# something like:
# triggers = {
#     always_run = "${timestamp()}"
#   }
# for null_resource

resource "helm_release" "example_chart" {
  depends_on = [
    null_resource.get_example_chart,
  ]
  name      = "example-chart"
  namespace = kubernetes_namespace.monitoring.metadata[0].name
  # chart = "oci://gitlab.example.com:4567/helm-charts/example-chart"
  # version = "0.1.0"
  chart = "/tmp/${local.example_chart_name}"

  set {
    name  = "yourVALUE"
    value = "test"
  }
}

@SvenHamers
Copy link

SvenHamers commented Jul 20, 2021

I have created a provider that can pull a helm oci registry chart to local chart by a data attribute. This way we don't have to use local resources until this is implemented in the helm provider :) https://registry.terraform.io/providers/SvenHamers/helmoci/latest

@ashtonian
Copy link

ashtonian commented Aug 11, 2021

is there anything blocking this? https://github.com/SvenHamers/terraform-provider-helmoci/blob/main/helmoci/data_oci.go looks to be whats missing, does it just need a pr?

related #655 #633

@SvenHamers
Copy link

@ashtonian I used stuff from the internals of helm package. So if you want to do the same here you can't just use the helm package. Don't think it is the right way to do in a official provider

@ashtonian
Copy link

@SvenHamers got it, thanks didn't realize it was still an issue upstream.

@ashtonian
Copy link

Looks like helm/helm#9782 which will hopefully be merged before September gets closer and "the internal/experimental/registry package has been stabilized. The public-facing Login, Logout, Pull, and Push methods all follow a common pattern, taking options and returning a result object." although still marked as experimental.

@zepellin
Copy link

Hello All.

With helm 3.7 being now released and containing support for OCI artifacts (still hidden behind HELM_EXPERIMENTAL_OCI=1), could this now be supported in the provider?

@so0k
Copy link

so0k commented Sep 17, 2021

there still seems to be a bug at least in the cli
helm/helm#10122 (comment)

@zliebersbach
Copy link

Helm 3.7 now supports this, AFAIK. My current workaround:

resource "null_resource" "pull_my_chart" {
  triggers = {
    random = uuid()
  }
  provisioner "local-exec" {
    command = <<-EOT
      export HELM_EXPERIMENTAL_OCI=1
      helm registry login registry.gitlab.com --username ${var.container_registry_username} --password ${var.container_registry_password}
      helm pull oci://registry.gitlab.com/my-org/my-chart --version ${local.my_chart_version} --untar -d /tmp
    EOT
  }
}

resource "helm_release" "my_release" {
  depends_on = [null_resource.pull_my_chart]
  name       = "my-release"

  chart   = "/tmp/my-chart"
  version = local.my_chart_version
}

@lindhe
Copy link

lindhe commented Oct 20, 2021

I want to point out that there was a breaking change to the Helm OCI manifest in 3.7, so charts pushed with <3.7 may not work with >=3.7. I think there is little point in implementing support for the 3.5 format.

@GiuseppeChiesa-TomTom
Copy link

I want to point out that there was a breaking change to the Helm OCI manifest in 3.7, so charts pushed with <3.7 may not work with >=3.7. I think there is little point in implementing support for the 3.5 format.

Do you have any link to this issue? does it apply also the other way around? so manifests generated by Helm >= 3.7 not being supported by Helm <3.7 ?

@zliebersbach
Copy link

See https://github.com/helm/helm/releases/tag/v3.7.0

@zepellin
Copy link

I believe that in newest 3.7.1 release the mediatype (different in helm version <3.7.0) was made backward compatible. So charts created by <3.7.0 should be installable with Helm 3.7.1.

@Blankf
Copy link

Blankf commented Nov 3, 2021

Hi Guys,

is there anyone able to have a look at this issue?
we are moving to aks and acr but are running into this issue now, and keeps us from moving forward :-(

hope someone is able to fix it.

@bluebrown
Copy link

bluebrown commented Nov 20, 2021

Helm 3.7 changed its api. Now it can do helm install oci://...

Also, as zepellin mentioned. If charts were packaged pre 3.7, they need to get repackaged and pushed for it to work. But thats a limitation of helm itself. You have the same problem if you use helm manually. Its mentioned in the release notes https://github.com/helm/helm/releases/tag/v3.7.0.
You can download them with 3.6 and untar them. And then save and push them with 3.7. Or if you are in control of the source, just save and push it with 3.7 to its own repo.

The below works for me with charts packaged by helm 3.7. Each chart has its own repo. In this example, emqx.

resource "helm_release" "emqx_cluster" {
  chart            = "oci://${var.helm_chart_acr_fqdn}/helm/v2/emqx"
  version          = "0.3.2"
  name             = "emqx"
  namespace        = "mqtt"
  create_namespace = true
  atomic           = true
  values           = var.emqx_values
}

@tomsnuvv
Copy link

@bluebrown Thanks for the example. It works for me with Helm 3.7 as well. I repackaged the helm chart and pushed it to an Azure Container Registry.

The following example uses an Azure Container Registry called helm-acr and the helm repository is called base-project.

resource "helm_release" "release" {
  chart            = "oci://helm-acr.azurecr.io/base-project"
  version          = "0.1.0"
  name             = "base-project"
  namespace        = "base-project"
  create_namespace = true
  atomic           = true
}

@chrissng
Copy link

May I know where can I find the official documentation on how to use oci:// in chart attribute?

In particular it will be great if there are information on how to:

  • enable the helm experimental mode
  • fetch credentials and do a helm registry login

@bluebrown
Copy link

bluebrown commented Nov 23, 2021

@chrissng Those infos are generally available in the helm docs.

I don't know, but my guess is Terraform will only officially support this if it's out of experimental stage. Although, it's already supported just because helm install works now like that, as you see from the above answer.

Here is an example of how to enable the experimental feature and login to ACR.

# enable the experimental feature
export HELM_EXPERIMENTAL_OCI=1

# fetch own credentials and login with helm
az acr login \
  --name myregistry \
  --expose-token \
  --output tsv \
  --query accessToken \
  2>/dev/null \
  | helm registry login myregistry.azurecr.io \
  --username 00000000-0000-0000-0000-000000000000 \
  --password-stdin

# or use a service principal
helm registry login myregistry.azurecr.io -u <acr_sp_id> -p <acr_sp_pwd>

# perform some operation against the registry
helm show values oci://myregistry.azurecr.io/helm/v2/emqx --version 0.3.2

@junaid-ali
Copy link

junaid-ali commented Nov 26, 2021

@bluebrown is that example for a public ACR repository? I'm trying with a private helm chart ECR registry but doesn't seem to be working for me.

Update: Never mind, it was due to older version of the helm provider, tried with the 2.4.1 and it's working for me as well.

@jodybro
Copy link

jodybro commented Nov 30, 2021

Did you need to pass any creds into the helm provider to log into that registry?

@bluebrown
Copy link

@jodybro, no you need to login helm manually outside of Terraform. Or you run those commands in something like null resource local exec.

@jodybro
Copy link

jodybro commented Nov 30, 2021

Ahh gotcha. Thanks!

@manobi
Copy link

manobi commented Dec 11, 2021

Anyone had success using helm_release attributes repository_username repository_password?
Without that helm binary is required and helm registry login have be run manually (as mentioned by @bluebrown).

data "aws_ecr_authorization_token" "token" {
  registry_id = "0000000000000"
}
resource "helm_release" "chart_release" {
  chart               = "oci://${trimprefix(data.aws_ecr_authorization_token.token.proxy_endpoint,"https://")}/chart-name"
  repository_username = data.aws_ecr_authorization_token.token.user_name
  repository_password = data.aws_ecr_authorization_token.token.password
  version             = "0.2.0"
  name                = "chart-name"
}

@robzr
Copy link

robzr commented Dec 21, 2021

Another way this can be done is by manually writing out the registry.json file; I'm having luck with this (admittedly ugly workaround). Note that HELM_CONFIG_PATH must be set and match var.helm.config_home; both provider.helm.registry_config_path and HELM_REGISTRY_CONFIG are not honored by the helm provider oddly (bug or provider docs are wrong), took me a while to figure this out.

provider "helm" {
   # TODO: Pending update to Helm provider allowing for OCI repo login
   #   https://github.com/hashicorp/terraform-provider-helm/issues/666
   #
   # This doesn't work with 2.4.1; requires HELM_CONFIG_PATH env var, but leaving
   # it in to force provider init to happen after config file is written
   registry_config_path = local_file.helm_registry_config.filename

   kubernetes {
     cluster_ca_certificate = data.terraform_remote_state.this.outputs.gke_cluster.ca_certificate
     host                   = data.terraform_remote_state.this.outputs.gke_cluster.host
     token                  = data.google_client_config.this.access_token
   }
 }

resource "helm_release" "this" {
   chart     = "${data.terraform_remote_state.this.outputs.repository.helm.repository}/${var.helm.chart}"
   name      = var.metadata.root
   namespace = var.namespace
   values    = [file("${path.module}/helm/values.${var.metadata.environment}.yaml")]
   version   = var.helm_chart_version
   wait      = true

   dynamic "set" {
     for_each = local.helm_value_uris

     content {
       name  = set.key
       value = local.stord_uri_lookups[set.value]
     }
   }
 }

resource "local_file" "helm_registry_config" {
   directory_permission = "0700"
   file_permission      = "0400"
   filename             = "${var.helm.config_home}/registry.json"
   sensitive_content = jsonencode({
     auths = {
       "https://${data.terraform_remote_state.this.outputs.repository.docker.host}" = {
         auth = base64encode(
           format(
             "%s:%s",
             data.terraform_remote_state.this.outputs.repository.helm.username,
             data.google_client_config.this.access_token,
           )
         )
       }
     }
   })
 }

@zenyui
Copy link

zenyui commented Jan 4, 2022

In case it helps anyone, got this to pull a chart from github packages with provider 2.4.1 (thanks @bluebrown for azure sample)

variable "github_username" {
  type = string
  sensitive = true
}

variable "github_token" {
  type = string
  sensitive = true
}

resource "null_resource" "helm_login" {
  triggers = {
    always_run = timestamp()
  }

  provisioner "local-exec" {
    command = <<-EOT
        HELM_EXPERIMENTAL_OCI=1 \
        helm registry login \
          -u ${var.github_username} \
          -p ${var.github_token} \
          https://ghcr.io
    EOT
  }
}

resource "helm_release" "release" {
  repository_username = var.github_username
  repository_password = var.github_token

  name = local.name
  chart = local.chart # oci://ghcr.io/foo/bar/...
  version = local.version

  namespace        = local.namespace
  create_namespace = false
  cleanup_on_fail  = true

  depends_on = [null_resource.helm_login]
}

@Kent1
Copy link

Kent1 commented Jan 14, 2022

Although using helm 3.7 cli work fine to pull and push to ECR, with terraform i cannot make it. I use the last helm provider, which normally use helm 3.7 but cannot make it work.

data "aws_ecr_authorization_token" "token" {
  registry_id = "0123456789"
}

resource "helm_release" "main" {
  chart           = "oci://0123456789.dkr.ecr.eu-west-1.amazonaws.com/v2/dns-crawler"
  repository_username = data.aws_ecr_authorization_token.token.user_name
  repository_password = data.aws_ecr_authorization_token.token.password
  repository = "0123456789.dkr.ecr.eu-west-1.amazonaws.com"
  ...

The error is always the same

helm_release.main: Modifying... [id=dns-crawler]

Error: failed to download "oci://0123456789.dkr.ecr.eu-west-1.amazonaws.com/v2/dns-crawler" at version "0.1.2"

  on main.tf line 183, in resource "helm_release" "main":
 183: resource "helm_release" "main" {

Anyone succeeded to make it work ?

PS : i exported the HELM_EXPERIMENTAL_OCI, i also tried login in with helm cli etc, but always the same error

@schra
Copy link

schra commented Jan 14, 2022

@Kent1 Did you re-package your Helm charts? See https://github.com/helm/helm/releases/tag/v3.7.0

In addition, a change to the experimental OCI manifest format was introduced, preventing Helm 3.7 from fetching charts built
with older versions of the experimental OCI feature. Users will need to re-package and upload their OCI charts when upgrading to Helm 3.7. This change does not affect standard Helm charts.

I had a similar tf error before repackaging the charts.

@Kent1
Copy link

Kent1 commented Jan 14, 2022

i did yes :(
nothing to change in the files of the Chart right ?

EDIT: Actually creating a new version worked .. I don't get it.. It was a brand new empty repo and i repackaged the helm chart juste before pushing.

i'll do some more test but thanks @schra

@rpf3
Copy link

rpf3 commented Feb 16, 2022

I'm having issues with this as well but I packaged and deployed the Helm chart using version 3.8.0 of the CLI. I get the error 401 Unauthorized from the resource when I set HELM_DEBUG=1 and try to apply my Terraform. I have tried both proposed solutions using the local-exec as well as the aws_ecr_authorization_token data resource but they both produce the same result. Has anyone been able to get this to work using 3.8.0? Hopefully if #827 is implemented this will be solved.

@zenyui
Copy link

zenyui commented Feb 16, 2022

I'm having issues with this as well but I packaged and deployed the Helm chart using version 3.8.0 of the CLI. I get the error 401 Unauthorized from the resource when I set HELM_DEBUG=1 and try to apply my Terraform. I have tried both proposed solutions using the local-exec as well as the aws_ecr_authorization_token data resource but they both produce the same result. Has anyone been able to get this to work using 3.8.0? Hopefully if #827 is implemented this will be solved.

@rpf3 I'm on github actions, and I had to force downgrade the host to 3.7.2 to get it to work (I think what's happening is the terraform resource uses the 3.7.X version of the golang lib, but the latest helm CLI 3.8.X backwards broke the OCI creds, still need to verify this is the cause)

here are my two github action steps before I apply terraform:

    - name: download specific helm version
      run: |
        wget https://get.helm.sh/helm-v3.7.2-linux-amd64.tar.gz
        tar -zxvf helm-v3.7.2-linux-amd64.tar.gz
        sudo mv linux-amd64/helm /usr/local/bin/helm
        helm version
    - name: helm login to private github oci registry
      env:
          GITHUB_USERNAME: XXXXX
          GITHUB_TOKEN: ${{ secrets.XXXX }}
      run: |
        export HELM_DEBUG=1
        export HELM_EXPERIMENTAL_OCI=1
        helm registry login \
          -u $GITHUB_USERNAME \
          -p $GITHUB_TOKEN \
          https://ghcr.io

@rpf3
Copy link

rpf3 commented Feb 16, 2022

@zenyui I think you may be correct. I just downgraded my local Helm client and was able to pull the chart from ECR successfully using the aws_ecr_authorization_token resource credentials.

@vmendiolalau
Copy link

vmendiolalau commented Mar 4, 2022

@rpf3, would you have a working snippet using aws_ecr_authorization_token at hand? I tried with Kent1's approach (#666 (comment)) and didn't work for me. I was still getting the same HTTP 401 you were having (I have helm v3.7.2).

I ended up creating a similar workaround to the ones proposed in the discussion, but would love to have a "cleaner" solution for this issue.

By the way, in case it is helpful, here's the workaround:

resource "null_resource" "login_to_ecr" {
  provisioner "local-exec" {
    interpreter = ["/bin/bash", "-c"]
    command = <<EOF
      aws ecr get-login-password \
        --region ${var.AWS_REGION} | helm registry login \
        --username AWS \
        --password-stdin ${var.AWS_ACCOUNT_ID}.dkr.ecr.${var.AWS_REGION}.amazonaws.com
EOF
  }
}

resource "helm_release" "my-svc" {
  name      = "my-svc"
  char      = "oci://${var.AWS_ACCOUNT_ID}.dkr.ecr.${var.AWS_REGION}.amazonaws.com/my-svc"
  version   = "0.1.0"
  namespace = "my-svc-ns"

  # extra params
  create_namespace = true
  atomic = true
  ...

  depends_on = [
    null_resource.login_to_ecr,
  ]
}

@rpf3
Copy link

rpf3 commented Mar 6, 2022

@vmendiolalau here's the outline of my code. I guess maybe my comment was unclear but I'm using the authorization token as the credentials in my null_resource that does the Helm login instead of calling aws ecr get-login-password.

#
# Helm Authentication
#

locals {
  registry_uri = format("%s.dkr.ecr.%s.amazonaws.com", var.account_id, var.primary_region)
}

data "aws_ecr_authorization_token" "token" {
  registry_id = var.account_id
}

resource "null_resource" "helm_login" {
  triggers = {
    always_run = timestamp()
  }

  provisioner "local-exec" {
    command = <<-EOT
      HELM_EXPERIMENTAL_OCI=1 \
      helm registry login \
        --username "${data.aws_ecr_authorization_token.token.user_name}" \
        --password "${data.aws_ecr_authorization_token.token.password}" \
        "${local.registry_uri}"
    EOT
  }
}

#
# Helm Release
#

resource "helm_release" "my_release" {
  name      = "my-app"
  chart     = format("oci://%s/my-repo-name", local.registry_uri)
  version   = "my-tag"
  namespace = kubernetes_namespace.my_namespace.metadata[0].name

  depends_on = [
    null_resource.helm_login
  ]
}

@cubasuarez
Copy link

Has anyone gotten this to work on gcp with artifact registry?

I keep getting
failed to authorize: failed to fetch oauth token: unexpected status: 401 Unauthorized

resource "null_resource" "ouath_repo" {
  triggers = {
    random = uuid()
  }
  provisioner "local-exec" {
    command = <<-EOT
      export HELM_EXPERIMENTAL_OCI=1
      gcloud auth print-access-token --project=myproject | helm registry login -u oauth2accesstoken  --password-stdin https://europe-west2-docker.pkg.dev
    EOT
  }
}

resource "helm_release" "springapp" {
  //depends_on = [null_resource.ouath_repo]
  name             = "springapp"
  version          = "0.0.0-feature-wif-SNAPSHOT"
  //repository      ="https://europe-west2-docker.pkg.dev/myproject/docker-helm"
  create_namespace = true
  namespace        = "default"
  wait             = false
  verify           = false
  chart            = "oci://europe-west2-docker.pkg.dev/myproject/docker-helm/springapp"
  values           = [
    //file("${path.module}/values.yml")
  ]
  set {
    name  = "spring.profiles.active"
    value = var.project
  }
}

provider "helm" {
  debug = true
  kubernetes {
    host                   = "https://${data.google_container_cluster.cluster.endpoint}"
    token                  = data.google_client_config.provider.access_token
    cluster_ca_certificate = base64decode(
    data.google_container_cluster.cluster.master_auth[0].cluster_ca_certificate,
    )
  }
}

@junaid-ali
Copy link

Hopefully, this will be resolved when #837 is merged

https://github.com/helm/helm/releases/tag/v3.8.0

@LP0101
Copy link

LP0101 commented Mar 11, 2022

Hopefully, this will be resolved when #837 is merged

https://github.com/helm/helm/releases/tag/v3.8.0

@junaid-ali

I built that branch and overrode the provider, but now I'm getting a new error:

│ Error: unable to lookup chart "oci://myregistry.azurecr.io/helm/mychart", missing registry client
│ 
│   with helm_release.test,
│   on main.tf line 32, in resource "helm_release" "test":
│   32: resource "helm_release" "test" {

And here's my terraform manifest:

resource "helm_release" "test" {

  name = "test"
  namespace = "luca-test" 
  chart = "oci://myregistry.azurecr.io/helm/mychart"
  version = "6.9.3"

  repository_username = "foo"
  repository_password = "bar"
}

Edit: I'm not super familiar with how helm handles OCI repositories, but it looks like the error is coming from here: https://github.com/helm/helm/blob/main/pkg/action/install.go#L679. Though I'm not sure why the client isn't defined. I can run helm install oci://... just fine.

@jrhouston
Copy link
Contributor

Thanks for trying out the above branch @LP0101 – there were some changes I had to make to set up the OCI registry client in the provider, and run the login operation if the username/password were specified. It should be working now if you want to try again with the latest push to the branch.

@LP0101
Copy link

LP0101 commented Mar 14, 2022

@jrhouston Looks like it works with OCI charts now. That was quick, thanks a lot!

@jrhouston
Copy link
Contributor

OCI support should now be available in the latest release. Thanks for your patience all 😄.

brk3 added a commit to brk3/caf-terraform-landingzones that referenced this issue Apr 6, 2022
This patch allows the use of ACR as a repository for helm charts.

Example usage:

helm_charts = {
  mychart = {
    name       = "mychart"
    chart      = "mychart"
    namespace  = "default"
    version    = "0.0.1"

    azure_container_registry = {
      lz_key   = "devops"
      key      = "devops_acr"
      username = "00000000-0000-0000-0000-000000000000"
    }
  }
}

Note, the version bump of the helm provider is for the recently added
oci support: hashicorp/terraform-provider-helm#666
@github-actions
Copy link

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 29, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.