Open pascalrobert opened 1 year ago
Hi Pascal, I'm Scott, a solutions architect here at 1Password. First, thank you for raising this issue. You're right, although the standard Terraform syntax for referencing nested attributes applies here in theory, the structure of custom 1Password items can make it a bit thorny. We are always working to improve our documentation and we will look for ways to improve our documentation with respect to retrieving specific keys or values from custom sections.
Now, to your specific issue: I'll have to admit that my Terraform chops are very rough, so my response may not be the most efficient way forward, but I've also reached out to the Secrets Automation developer team to see if they have better suggestions. I also hope I understand your question correctly. It sounds to me as if you'd like to retrieve a specific value from a custom field nested in a section. Is that about right?
If so, here's what worked for me, given the following.
I take onepassword_item
resource defined in the following way:
resource "onepassword_item" "demo_sections" {
vault = var.demo_vault
title = "Demo Terraform Item with Sections"
category = "login"
username = "test@example.com"
section {
label = "Terraform_Section"
field {
label = "API_KEY"
type = "CONCEALED"
value = "Gr34tP4$$word"
}
field {
label = "HOSTNAME"
value = "example.com"
}
}
section {
label = "Terraform Second Section"
field {
label = "App Specific Password"
type = "CONCEALED"
password_recipe {
length = 40
symbols = false
}
}
field {
label = "User"
value = "demo"
}
}
}
And a corresponding data block as follows:
data "onepassword_item" "get_pass_example" {
vault = var.demo_vault
uuid = onepassword_item.demo_sections.uuid
}
Now I just tested this in terraform console
so some tweaks may be required if you're including this in a plan, but the following worked to retrieve the value of the API_KEY
field nested in the Terraform_Section
section.
data.onepassword_item.get_pass_example.section[index(data.onepassword_item.get_pass_example.section.*.label, "Terraform_Section")].field[0].value
That returns Gr34tP4$$word
, as expected.
Now I notice that you are asking for a specific key, rather than values.... if that is actually the case, then you could get an array of keys for the Terraform_Section
section:
keys(data.onepassword_item.get_pass_example.section[index(data.onepassword_item.get_pass_example.section.*.label, "Terraform_Section")].field[0])
and a specific key from that array with standard index subscripting on the output from the keys()
call. E.g., to get the 0th item:
keys(data.onepassword_item.get_pass_example.section[index(data.onepassword_item.get_pass_example.section.*.label, "Terraform_Section")].field[0])[0]
Now as I said, I'm no Terraform expert myself, so this may be a roundabout way of getting to your destination. I'll pass along any additional suggestions from our developers when available. But hopefully this is a start.
And again, thank you for your suggestions for improving our documentation.
Hi Pascal, First of all, I should apologize, since I think I misunderstood your request when you were asking about retrieving a key. I had assumed you meant "key" in the key/value pair sense.
Alas, one of our devs correctly understood your request and provided the following. The syntax to retrieve the value of the secret is nearly similar to my first value-retrieval syntax but is nested in a more useful output
block:
Here’s an example terraform file that gets from an item the value of the field title
from section off
(the item is looked up by item and vault UUIDs)
terraform {
required_providers {
onepassword = {
source = "1Password/onepassword"
version = "~> 1.1.4"
}
}
}
provider "onepassword" {
url = "http://localhost:8000/"
}
data "onepassword_item" "example" {
vault = "ar3v2gmnw73p4bhkphr7t6rv44"
uuid = "257ueonb6vek5fg4uwzl2qc73y"
}
output "custom_field" {
value = data.onepassword_item.example.section[index(data.onepassword_item.example.section.*.label, "off")].field[index(data.onepassword_item.example.section[index(data.onepassword_item.example.section.*.label, "off")].field.*.label, "title")].value
}
There may be a slightly less syntactically-verbose way to drill down into that field but this was what we were able to make work most reliably.
I hope that helps you out a bit!
We'll also file an issue with our docs team to explore options for improving our terraform documentation with respect to this type of task.
Hi Scott,
Your reply helped a lot, thanks! I did something like this:
data "onepassword_item" "secrets" {
vault = data.onepassword_vault.aw.uuid
title = "secrets"
}
locals {
secrets_bd = data.onepassword_item.secrets.section[index(data.onepassword_item.secrets.section.*.label, "BD")]
}
local.secrets_bd.field[index(local.secrets_bd.field.*.label, "majbds-mdp")].value
```
It does work, except if the label or the section name contains a space in it, or the label goes over a specific length, I get errors like this:
│ Error: Error in function call │ │ on asg.tf line 95, in module "gabarit_lancement": │ 95: mp_bd_datadog : local.secrets_bd.field[index(local.secrets_bd.field.*.label, "awDatabase-datadog-mdp")].value, │ ├──────────────── │ │ while calling index(list, value) │ │ local.secrets_bd.field is list of object with 7 elements │ │ Call to function "index" failed: item not found.
Heey @pascalrobert,
Glad to see that the suggested snippet that we've suggested worked for you and you even went beyond and made it friendlier. I really appreciate it and we should document such example in the repo as well.
Also, I appreciate that you've identified some scenarios in which the provider doesn't work as expected. I will raise them with my team and try to look into them. We will keep you posted when we have new insight for you regarding these.
Thanks for this, I was looking for an example of how to use a custom section. My problem now is that I haven't seen how to set a custom field of type DATE - the resource completes fine, but the field never appears in the 1password database.
section {
label = "Custom"
field {
label = "Expiry"
type = "DATE"
value = formatdate("YYYY-MM-DD",expirytimestamp)
}
}
Hello,
After update to 1.2.0 this no longer works:
resource "onepassword_item" "vm-admin" {
vault = data.onepassword_vault.vault.uuid
title = lower(var.vm-name)
category = "login"
username = "deploy"
section {
label = "XXX Data"
field {
label = "Deployment notes"
purpose = "NOTES"
value = "Local admin generated by Terraform"
}
field {
label = "IP"
type = "STRING"
value = phpipam_address.newip.ip_address
}
}
tags = ["terraform", "auto-created", "local-admin", "Linux"]
password_recipe {
length = 40
symbols = false
}
}
It does create the "XXX Data" section, but without any data in it.
Hey @scholdan, We've just merged a fix for that with https://github.com/1Password/terraform-provider-onepassword/pull/100 and we're planning to make a release with this fix soon.
And the fix has been pushed with the 1.2.1 release. So you should be able to create fields within a section again @scholdan. 😄
@pascalrobert @scottisloud, thank you for providing your examples!
I decided to show how I adapted it for my needs. Below is an example of how to retrieve specific data from item.
# Retrieve your vault using the specified name
data "onepassword_vault" "devops_vault" {
name = var.op_vault
}
# Retrieve the item "Proxmox PVE01" from the main vault
data "onepassword_item" "proxmox_pve01" {
vault = data.onepassword_vault.devops_vault.uuid
title = "Proxmox PVE01"
}
locals {
# Store the section labeled "API" from item "Proxmox PVE01" in a local variable for shortened string references
section_api = data.onepassword_item.proxmox_pve01.section[index(data.onepassword_item.proxmox_pve01.section.*.label, "API")]
# Store the field value of the section "API" in a local variable for shortened string references
pve01_api = local.section_api.field
# Extract the API URL field value from the "API" section of the Proxmox PVE01 item and store it in a local variable
pm_api_url = local.pve01_api[index(local.pve01_api.*.label, "pm_api_url")].value
# Extract the API token secret field value from the "API" section of the Proxmox PVE01 item and store it in a local variable
pm_api_token_secret = local.pve01_api[index(local.pve01_api.*.label, "pm_api_token_secret")].value
# Extract the API token ID field value from the "API" section of the Proxmox PVE01 item and store it in a local variable
pm_api_token_id = local.pve01_api[index(local.pve01_api.*.label, "pm_api_token_id")].value
}
# Output the Proxmox PVE01 API URL
output "pm_api_url" {
value = local.pm_api_url
}
# Output the Proxmox PVE01 API token secret
output "pm_api_token_secret" {
value = local.pm_api_token_secret
}
# Output the Proxmox PVE01 API token ID
output "pm_api_token_id" {
value = local.pm_api_token_id
}
@mrkhachaturov thank you for the nudge. using a map can improve readability.
locals {
section_api = data.onepassword_item.proxmox_pve01.section[index(data.onepassword_item.proxmox_pve01.section.*.label, "API")]
pve01_api = { for field in local.section_api.field : field.label => field.value }
pm_api_url = local.pve01_api["pm_api_url"]
pm_api_token_secret = local.pve01_api["pm_api_token_secret"]
pm_api_token_id = local.pve01_api["pm_api_token_id"]
}
We need more complex examples. For example, how to fetch an key from an item? I tried something like this:
data "onepassword_item" "secrets" { vault = data.onepassword_vault.aw.uuid title = "secrets" }
data.onepassword_item.secrets.section[index(data.onepassword_item.secrets.section.*.label, "my-label")]
Didn't work. Also tried with:
data.onepassword_item.secrets.section[index(data.onepassword_item.secrets.section.*.field.label, "my-label")]
Didn't work either. So what's the correct way to get one key out of an item?