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 Section Fields LookUp by Title #117

Open
yordis opened this issue Dec 4, 2023 · 4 comments · May be fixed by #120
Open

Allow Section Fields LookUp by Title #117

yordis opened this issue Dec 4, 2023 · 4 comments · May be fixed by #120

Comments

@yordis
Copy link

yordis commented Dec 4, 2023

Summary

Allow Section Fields LookUp by Title when using data "onepassword_item" resource.

Use cases

As a programmer, I would like to have a way to lookup a Section Field by Title.

Given the following secret:

{
  "overview": {
    "title": "my-title",
  },
  "details": {
    "sections": [
      {
        "name": "add more",
        "title": "",
        "fields": [
          {
            "t": "DO_ACCESS_TOKEN",
            "k": "concealed"
          },
          {
            "t": "DO_SPACES_ACCESS_ID",
            "k": "concealed"
          },
          {
            "t": "DO_SPACES_ACCESS_KEY",
            "k": "concealed"
          },
        ]
      }
    ]
  }
}

I would like to be able to use the title (in this case DO_ACCESS_TOKEN) of the field.

data "onepassword_item" "main" {}

resource "terraform_data" "do_access_token" {
  input = data.onepassword_item.my-title.section.fields["DO_ACCESS_TOKEN"]
}

Proposed solution

Introduce fields (plural), or break change (🤷🏻) in order to look up the fields by title.

Otherwise, document how I suppose to do this because my skills are limited and I can not find a simple way to do it.
I am not sure what I am doing wrong here.

Is there a workaround to accomplish this today?

I think that, you loop thru the fields, match in the field name, get the value back into a local and then use it! 😭

References & Prior Work

@yordis yordis linked a pull request Dec 9, 2023 that will close this issue
@kitforbes
Copy link

I started playing with the provider last night and wanted behaviour like this. I've created a simple wrapper in my project to re-shape the object that we get from the onepassword_item data source.

Some caveats:

  1. A "section" name (label) must be unique
  2. A "field" name (label) within a section (either top-level ("") or custom) must be unique
  3. I've only tested this with a "password" type object so far, so the example below will not fit every category. Extending it should be simple enough.

If there are duplicates, Terraform will fail due to a non-unique key.

module/variables.tf

variable "title" {
  type = string
}

variable "vault_uuid" {
  type = string
}

module/main.tf

terraform {
  required_version = ">= 1.0.0"

  required_providers {
    onepassword = {
      source = "1Password/onepassword"
    }
  }
}

data "onepassword_item" "main" {
  vault = var.vault_uuid
  title = var.title
}

locals {
  fields = { for f in data.onepassword_item.main.section[0].field : f.label => {
      id = f.id
      purpose = f.purpose
      type = f.type
      value = f.value
    }
  }

  sections = { for s in data.onepassword_item.main.section : s.label => {
    id = s.id
    fields = { for f in s.field : f.label => {
      id = f.id
      purpose = f.purpose
      type = f.type
      value = f.value
    } }
  } if s.label != "" }
}

module/outputs.tf

output "category" {
  value = data.onepassword_item.main.category
}

output "database" {
  value = data.onepassword_item.main.database
}

output "fields" {
  value = local.fields
}

output "hostname" {
  value = data.onepassword_item.main.hostname
}

output "id" {
  value = data.onepassword_item.main.id
}

output "note_value" {
  value     = data.onepassword_item.main.note_value
  sensitive = true
}

output "password" {
  value     = data.onepassword_item.main.password
  sensitive = true
}

output "port" {
  value = data.onepassword_item.main.port
}

output "sections" {
  value = local.sections
}

output "tags" {
  value = data.onepassword_item.main.tags
}

output "title" {
  value = data.onepassword_item.main.title
}

output "type" {
  value = data.onepassword_item.main.type
}

output "url" {
  value = data.onepassword_item.main.url
}

output "username" {
  value = data.onepassword_item.main.username
}

output "uuid" {
  value = data.onepassword_item.main.uuid
}

output "vault" {
  value = data.onepassword_item.main.vault
}

Consume the module like this:

data "onepassword_vault" "vault" {
  name = "My Vault"
}

module "test_item" {
  source = "./module"

  vault_uuid = data.onepassword_vault.vault.uuid
  title      = "Test"
}

output "value_from_text_field_in_section" {
  value = module.test_item.sections["Section One"].fields["text"].value
}

The item used in this example has this layout:
image

@dannysauer
Copy link

dannysauer commented May 15, 2024

The module is way prettier than what I did. Given a onepassword_item named determined_ci_github (hence the dcg prefix):

locals {
  dcg_section_label = "Tokens"
  dcg_field_id      = "jxu6aak6lkhdxij6whyqels42u"
  dcg_sections      = data.onepassword_item.determined_ci_github.section
  dcg_section_index = index(local.dcg_sections.*.label, local.dcg_section_label)
  dcg_fields        = local.dcg_sections[local.dcg_section_index].field
  dcg_field_index   = index(local.dcg_fields.*.id, local.dcg_field_id)
  dcg_field         = local.dcg_fields[local.dcg_field_index]
}

So I find the section with the desired label, then in that section I find the field with the given ID (since it has a name with weird chars). Then afterwards, I can reference local.dcg_field.value. Probably should've added dcg_value to locals to shorten that up a bit more. Meh.

This approach becomes a real mess when you want multiple fields from one item. The module is likely much better for that.

@ekostjuk
Copy link

ekostjuk commented May 28, 2024

A bit simpler workaround, but still, having to boilerplate this all around the code is not clean. (using separate vault id verification here)

data onepassword_vault ops {
  name = var.ops_vault
}
data onepassword_item service {
  vault = split("/", data.onepassword_vault.ops.id)[1]
  title = "service"
}
locals {
  service = {for k1, v1 in data.onepassword_item.service.section : v1.label =>  {for k2, v2 in v1.field : v2.label => v2.value}}
}

@Eugst
Copy link

Eugst commented Nov 5, 2024

Thank you @kitforbes!!! Great solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants