spiffe / spire

The SPIFFE Runtime Environment
https://spiffe.io
Apache License 2.0
1.79k stars 473 forks source link

Make JSON configuration a first class citizen #2808

Open jonringer opened 2 years ago

jonringer commented 2 years ago

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"
  }
}
jonringer commented 2 years ago

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

evan2645 commented 2 years ago

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

jonringer commented 2 years ago

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 commented 2 years ago

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.

blaggacao commented 2 years ago

I would suggest to accept both:

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.

StupidScience commented 2 years ago

@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.

blaggacao commented 2 years ago

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).

rturner3 commented 1 year ago

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

github-actions[bot] commented 5 months ago

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