Arbiter is a tool to browse terraform outputs. It provides a web UI for browsing
through terraform state in directory format. It's designed to be able to work
with a selection of different named storage "backends". The main interface is a
configurable http.Handler
so you can embed or run it as you deem necessary.
Here's an example of using arbiter with a local filesystem.
package main
import (
"log"
"net/http"
"os"
"github.com/enova/arbiter"
)
func main() {
state := os.DirFS(os.Getenv("TF_STATE_DIR"))
backends := arbiter.NewBackendList()
backends.AddState("local", state)
h, err := arbiter.NewHandler(backends, log.Default())
if err != nil {
panic(err)
}
log.Fatal(http.ListenAndServe(os.Getenv("ADDR"), h))
}
If you would rather serve arbiter from a nested path, make sure to use
http.StripPrefix
like so
h, err := arbiter.NewHandler(backends, log.Default())
if err != nil {
panic(err)
}
mux := http.NewServeMux()
mux.Handle("/arbiter/", http.StripPrefix("/arbiter", h))
log.Fatal(http.ListenAndServe(os.Getenv("ADDR"), mux))
The BackendListFromJSON
function can be used to initialize a list of backends
based on a JSON configuration. Currently s3 is the only supported backend.
Implementation uses s3fs and expects
credentials to be available in either env vars or configuration files in
accordance with the aws go SDK v1.
Assuming you had a local config.json
with the following contents:
[
{
"name": "production",
"type": "s3",
"connection_info": {
"bucket_name": "my-production-bucket"
}
},
{
"name": "staging",
"type": "s3",
"connection_info": {
"bucket_name": "my-staging-bucket",
"role_arn": "role-for-use-by-sts"
}
}
]
You could read it like so
package main
import (
"fmt"
"os"
"github.com/enova/arbiter"
)
func main() {
f, err := os.Open("./config.json")
if err != nil {
panic(err)
}
backends, err := arbiter.BackendListFromJSON(f)
if err != nil {
panic(err)
}
for _, name := range backends.Names() {
fmt.Println("registered: ", name)
}
}
For a simple terraform state with two sub-directories, prod and staging
Top level search page:
Outputs in a sub directory:
The main assumption arbiter makes is that all of your outputs, including those marked sensitive, are safe to read. If you need access control you can implement it as a middleware, but arbiter doesn't natively have any.