spire icon indicating copy to clipboard operation
spire copied to clipboard

Make JSON configuration a first class citizen

Open jonringer opened this issue 2 years ago • 9 comments

Issue

Although spire supports json as a file format for server and agent configuration, it's not ergonomic to use. It gets parsed as the HCL equivalent which is quite ugly, and the format looks to be very error prone (e.g. usage of lists wrapping every scope).

~~Furthermore, I haven't seen an example where HCL's ability to have duplicated block names is a valid configuration (e.g. two sql DataStore entries), so the json schema feels misaligned with the desired configuration shape (i.e should be nested dictionaries, not nested arrays).~~ Node attestors can have many plugins. However, HCL v2 should also be able to handle this use case example

Motivation

Allow for other tools which can target json as a configuration option. Tools like Nix, Dhall, Cue and others can usually export a json configuration file, but are not compatible with "HCL-style json".

Personally, I'm interested in making a NixOS module, generally we expose module options (example nginx options). And it would be nice to use a more json-friendly format which will resemble more standard json.

Example

example spire.hcl

server {
    trust_domain = "example.org"

    bind_address = "0.0.0.0"
    bind_port = "8081"
    log_level = "INFO"
    data_dir = ".data/"
    default_svid_ttl = "6h"
    ca_ttl = "72h"
    ca_subject {
        country = ["US"]
        organization = ["SPIRE"]
        common_name = ""
    }
}

plugins {
    DataStore "sql" {
        plugin_data {
            database_type = "sqlite3"
            connection_string = ".data/datastore.sqlite3"
        }
    }
    NodeAttestor "join_token" {
        plugin_data {}
    }
    KeyManager "disk" {
        plugin_data {
            keys_path = ".data/keys.json"
        }
    }
}

as "HCL-style" spire.json:

{
  "plugins": [
    {
      "DataStore": [
        {
          "sql": [
            {
              "plugin_data": [
                {
                  "connection_string": ".data/datastore.sqlite3",
                  "database_type": "sqlite3"
                }
              ]
            }
          ]
        }
      ],
      "KeyManager": [
        {
          "disk": [
            {
              "plugin_data": [
                {
                  "keys_path": ".data/keys.json"
                }
              ]
            }
          ]
        }
      ],
      "NodeAttestor": [
        {
          "join_token": [
            {
              "plugin_data": [
                {}
              ]
            }
          ]
        }
      ]
    }
  ],
  "server": [
    {
      "bind_address": "0.0.0.0",
      "bind_port": "8081",
      "ca_subject": [
        {
          "common_name": "",
          "country": [
            "US"
          ],
          "organization": [
            "SPIRE"
          ]
        }
      ],
      "ca_ttl": "72h",
      "data_dir": ".data/",
      "default_svid_ttl": "6h",
      "log_level": "INFO",
      "trust_domain": "example.org"
    }
  ]
}

Ideally, the json file would just be:

{
  "plugins": {
    "DataStore": {
      "sql": {
        "plugin_data": {
          "connection_string": ".data/datastore.sqlite3",
          "database_type": "sqlite3"
        }
      }
    },
    "KeyManager": {
      "disk": {
        "plugin_data": {
          "keys_path": ".data/keys.json"
        }
      }
    },
    "NodeAttestor": {
      "join_token": {
        "plugin_data": {}
      }
    }
  },
  "server": {
    "bind_address": "0.0.0.0",
    "bind_port": "8081",
    "ca_subject": {
      "common_name": "",
      "country": [ "US" ],
      "organization": [ "SPIRE" ]
    },
    "ca_ttl": "72h",
    "data_dir": ".data/",
    "default_svid_ttl": "6h",
    "log_level": "INFO",
    "trust_domain": "example.org"
  }
}
  • Version: 1.2
  • Platform: Linux jon-desktop 5.4.180 #1-NixOS SMP Wed Feb 16 11:52:54 UTC 2022 x86_64 GNU/Linux
  • Subsystem: server and agent conf file

jonringer avatar Feb 28 '22 07:02 jonringer

Looks like this might be achieved by using hcl v2 https://github.com/hashicorp/hcl

jonringer avatar Mar 09 '22 22:03 jonringer

Hi @jonringer .. our hope with using hcl was to have both something a bit friendlier than straight JSON but also to support JSON for machine generated cases. Unfortunately, I feel it has failed more or less on both fronts :(

Changing is a major compatibility challenge. And not to sound too pointy, but these kinds of issues are hard to defend .. the next person wants YAML or something else!

We've had a look at hcl v2, and (again) unfortunately it breaks some core syntax for us.

Furthermore, I haven't seen an example where HCL's ability to have duplicated block names is a valid configuration (e.g. two sql DataStore entries)

This is supported and idiomatic for SPIRE Server node attestors and node resolvers. Similarly, supported and idiomatic for SPIRE Agent workload attestors.

Frankly, I think we are between a rock and a hard spot as we're leaning on features of a deprecated HCL version. We need a long term solution. Moving to HCL v2 is probably the right answer, but we need help in trying to figure out how to get there, and plan the migration across several versions. Detection of the "bad" patterns, deprecation warnings, compatibility shims, comprehensive documentation updates etc, are all necessary parts of such an effort

evan2645 avatar Mar 09 '22 23:03 evan2645

Changing is a major compatibility challenge. And not to sound too pointy, but these kinds of issues are hard to defend .. the next person wants YAML or something else!

Yes, but HCL v2 seems to be able to parse HCL and (canonical) json. Since "yaml is also json", it should be "easy" to use one or the other.

This is supported and idiomatic for SPIRE Server node attestors and node resolvers. Similarly, supported and idiomatic for SPIRE Agent workload attestors.

Hadn't got around to playing around with node attestors, but that use case makes sense to me.

We need a long term solution

Supporting json at least allows for people to target json as their configuration target. I'm not trying to influence what should be the configuration happy path, just want json to be a more supported path. :)

Detection of the "bad" patterns, deprecation warnings, compatibility shims, comprehensive documentation updates etc, are all necessary parts of such an effort

Yea, deprecation mechanisms are a PITA; and increase complexity if you try to gracefully handle it.

jonringer avatar Mar 10 '22 00:03 jonringer

My first instinct would be to have an additional version field to the top of the configuration:

# config.json
{
  "version": "2",
  ...
}

The problem is that spire does structured parsing, so you would need to know the structure of configuration file before you attempt to decode it.

Yea, I'm not sure, this isn't an easy issue.

jonringer avatar Mar 10 '22 00:03 jonringer

I would suggest to accept both:

  • JSON/YAML
  • TOML (for leaving comments and easier on the eyes)

HCL, not being able to claim to be some sort of "standard" format, continues to be the place between a rock and a hard spot.

All config languages (jsonnet/dhall/nickel/cue), including HCL, are json serializable.

blaggacao avatar Mar 10 '22 21:03 blaggacao

@jonringer I've checked briefly and "ideal" json require few tweaks in plugin section to be working

{
    "plugins": {
        "DataStore": [
            {
                "sql": {
                    "plugin_data": {
                        "connection_string": ".data/datastore.sqlite3",
                        "database_type": "sqlite3"
                    }
                }
            }
        ],
        "KeyManager": [
            {
                "disk": {
                    "plugin_data": {
                        "keys_path": ".data/keys.json"
                    }
                }
            }
        ],
        "NodeAttestor": [
            {
                "join_token": {
                    "plugin_data": {}
                }
            }
        ]
    },
    "server": {
        "bind_address": "0.0.0.0",
        "bind_port": "8081",
        "ca_subject": {
            "common_name": "",
            "country": [
                "US"
            ],
            "organization": [
                "SPIRE"
            ]
        },
        "ca_ttl": "72h",
        "data_dir": ".data/",
        "default_svid_ttl": "6h",
        "log_level": "INFO",
        "trust_domain": "example.org"
    }
}

But in general I agree that would be great to have more idiomatic json support.

StupidScience avatar May 10 '22 11:05 StupidScience

The problem is that it is hard to handle lists in config management as list items aren't stably identified (only by a potentially mutating index).

blaggacao avatar Jul 09 '22 00:07 blaggacao

This may be addressed with the migration from HCL v1 to HCL v2: #4042

rturner3 avatar May 22 '23 19:05 rturner3

This issue is stale because it has been open for 365 days with no activity.

github-actions[bot] avatar May 21 '24 22:05 github-actions[bot]