Skip to content

Commit

Permalink
Add SPIRE Bundle APIs (#478)
Browse files Browse the repository at this point in the history
* Add bundle functions

Signed-off-by: Maia Iyer <[email protected]>

* add v1 apis

Signed-off-by: Maia Iyer <[email protected]>

* format nit

Signed-off-by: Maia Iyer <[email protected]>

* Nit uri fix

Signed-off-by: Maia Iyer <[email protected]>

* gofmtted code

Signed-off-by: Maia Iyer <[email protected]>

---------

Signed-off-by: Maia Iyer <[email protected]>
  • Loading branch information
maia-iyer authored Aug 13, 2024
1 parent 1371d54 commit 243788e
Show file tree
Hide file tree
Showing 3 changed files with 325 additions and 14 deletions.
107 changes: 107 additions & 0 deletions api/agent/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"google.golang.org/grpc/credentials/insecure"

agent "github.com/spiffe/spire-api-sdk/proto/spire/api/server/agent/v1"
bundle "github.com/spiffe/spire-api-sdk/proto/spire/api/server/bundle/v1"
debugServer "github.com/spiffe/spire-api-sdk/proto/spire/api/server/debug/v1"
entry "github.com/spiffe/spire-api-sdk/proto/spire/api/server/entry/v1"
types "github.com/spiffe/spire-api-sdk/proto/spire/api/types"
Expand Down Expand Up @@ -215,6 +216,112 @@ func (s *Server) GetTornjakServerInfo(inp GetTornjakServerInfoRequest) (*GetTorn
return (*GetTornjakServerInfoResponse)(&s.SpireServerInfo), nil
}

// Bundle APIs
type GetBundleRequest bundle.GetBundleRequest
type GetBundleResponse types.Bundle

func (s *Server) GetBundle(inp GetBundleRequest) (*GetBundleResponse, error) { //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
inpReq := bundle.GetBundleRequest(inp) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
var conn *grpc.ClientConn
conn, err := grpc.Dial(s.SpireServerAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, err
}
defer conn.Close()
client := bundle.NewBundleClient(conn)

bundle, err := client.GetBundle(context.Background(), &inpReq)
if err != nil {
return nil, err
}

return (*GetBundleResponse)(bundle), nil
}

type ListFederatedBundlesRequest bundle.ListFederatedBundlesRequest
type ListFederatedBundlesResponse bundle.ListFederatedBundlesResponse

func (s *Server) ListFederatedBundles(inp ListFederatedBundlesRequest) (*ListFederatedBundlesResponse, error) { //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
inpReq := bundle.ListFederatedBundlesRequest(inp) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
var conn *grpc.ClientConn
conn, err := grpc.Dial(s.SpireServerAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, err
}
defer conn.Close()
client := bundle.NewBundleClient(conn)

bundle, err := client.ListFederatedBundles(context.Background(), &inpReq)
if err != nil {
return nil, err
}

return (*ListFederatedBundlesResponse)(bundle), nil
}

type CreateFederatedBundleRequest bundle.BatchCreateFederatedBundleRequest
type CreateFederatedBundleResponse bundle.BatchCreateFederatedBundleResponse

func (s *Server) CreateFederatedBundle(inp CreateFederatedBundleRequest) (*CreateFederatedBundleResponse, error) { //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
inpReq := bundle.BatchCreateFederatedBundleRequest(inp) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
var conn *grpc.ClientConn
conn, err := grpc.Dial(s.SpireServerAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, err
}
defer conn.Close()
client := bundle.NewBundleClient(conn)

bundle, err := client.BatchCreateFederatedBundle(context.Background(), &inpReq)
if err != nil {
return nil, err
}

return (*CreateFederatedBundleResponse)(bundle), nil
}

type UpdateFederatedBundleRequest bundle.BatchUpdateFederatedBundleRequest
type UpdateFederatedBundleResponse bundle.BatchUpdateFederatedBundleResponse

func (s *Server) UpdateFederatedBundle(inp UpdateFederatedBundleRequest) (*UpdateFederatedBundleResponse, error) { //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
inpReq := bundle.BatchUpdateFederatedBundleRequest(inp) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
var conn *grpc.ClientConn
conn, err := grpc.Dial(s.SpireServerAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, err
}
defer conn.Close()
client := bundle.NewBundleClient(conn)

bundle, err := client.BatchUpdateFederatedBundle(context.Background(), &inpReq)
if err != nil {
return nil, err
}

return (*UpdateFederatedBundleResponse)(bundle), nil
}

type DeleteFederatedBundleRequest bundle.BatchDeleteFederatedBundleRequest
type DeleteFederatedBundleResponse bundle.BatchDeleteFederatedBundleResponse

func (s *Server) DeleteFederatedBundle(inp DeleteFederatedBundleRequest) (*DeleteFederatedBundleResponse, error) { //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
inpReq := bundle.BatchDeleteFederatedBundleRequest(inp) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
var conn *grpc.ClientConn
conn, err := grpc.Dial(s.SpireServerAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, err
}
defer conn.Close()
client := bundle.NewBundleClient(conn)

bundle, err := client.BatchDeleteFederatedBundle(context.Background(), &inpReq)
if err != nil {
return nil, err
}

return (*DeleteFederatedBundleResponse)(bundle), nil
}

/*
Agent
Expand Down
216 changes: 210 additions & 6 deletions api/agent/server.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package api

import (
"crypto/tls"
"encoding/json"
"fmt"
"io"
Expand All @@ -11,7 +12,6 @@ import (
"path/filepath"
"strings"
"time"
"crypto/tls"

backoff "github.com/cenkalti/backoff/v4"
"github.com/gorilla/mux"
Expand All @@ -20,9 +20,9 @@ import (
"github.com/hashicorp/hcl/hcl/token"
"github.com/pkg/errors"

agentdb "github.com/spiffe/tornjak/pkg/agent/db"
"github.com/spiffe/tornjak/pkg/agent/authentication/authenticator"
"github.com/spiffe/tornjak/pkg/agent/authorization"
agentdb "github.com/spiffe/tornjak/pkg/agent/db"
)

type Server struct {
Expand All @@ -36,9 +36,9 @@ type Server struct {
TornjakConfig *TornjakConfig

// Plugins
Db agentdb.AgentDB
Db agentdb.AgentDB
Authenticator authenticator.Authenticator
Authorizer authorization.Authorizer
Authorizer authorization.Authorizer
}

// config type, as defined by SPIRE
Expand Down Expand Up @@ -406,6 +406,207 @@ func (s *Server) entryDelete(w http.ResponseWriter, r *http.Request) {
}
}

// Bundle APIs
func (s *Server) bundleGet(w http.ResponseWriter, r *http.Request) {
var input GetBundleRequest
buf := new(strings.Builder)

n, err := io.Copy(buf, r.Body)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
data := buf.String()

if n == 0 {
input = GetBundleRequest{}
} else {
err := json.Unmarshal([]byte(data), &input)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

ret, err := s.GetBundle(input) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusInternalServerError)
return
}

cors(w, r)
je := json.NewEncoder(w)
err = je.Encode(ret)
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

func (s *Server) federatedBundleList(w http.ResponseWriter, r *http.Request) {
var input ListFederatedBundlesRequest
buf := new(strings.Builder)

n, err := io.Copy(buf, r.Body)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
data := buf.String()

if n == 0 {
input = ListFederatedBundlesRequest{}
} else {
err := json.Unmarshal([]byte(data), &input)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

ret, err := s.ListFederatedBundles(input) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusInternalServerError)
return
}

cors(w, r)
je := json.NewEncoder(w)
err = je.Encode(ret)
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

func (s *Server) federatedBundleCreate(w http.ResponseWriter, r *http.Request) {
var input CreateFederatedBundleRequest
buf := new(strings.Builder)

n, err := io.Copy(buf, r.Body)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
data := buf.String()

if n == 0 {
input = CreateFederatedBundleRequest{}
} else {
err := json.Unmarshal([]byte(data), &input)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

ret, err := s.CreateFederatedBundle(input) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusInternalServerError)
return
}

cors(w, r)
je := json.NewEncoder(w)
err = je.Encode(ret)
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

func (s *Server) federatedBundleUpdate(w http.ResponseWriter, r *http.Request) {
var input UpdateFederatedBundleRequest
buf := new(strings.Builder)

n, err := io.Copy(buf, r.Body)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
data := buf.String()

if n == 0 {
input = UpdateFederatedBundleRequest{}
} else {
err := json.Unmarshal([]byte(data), &input)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

ret, err := s.UpdateFederatedBundle(input) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusInternalServerError)
return
}

cors(w, r)
je := json.NewEncoder(w)
err = je.Encode(ret)
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

func (s *Server) federatedBundleDelete(w http.ResponseWriter, r *http.Request) {
var input DeleteFederatedBundleRequest
buf := new(strings.Builder)

n, err := io.Copy(buf, r.Body)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
data := buf.String()

if n == 0 {
input = DeleteFederatedBundleRequest{}
} else {
err := json.Unmarshal([]byte(data), &input)
if err != nil {
emsg := fmt.Sprintf("Error parsing data: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

ret, err := s.DeleteFederatedBundle(input) //nolint:govet //Ignoring mutex (not being used) - sync.Mutex by value is unused for linter govet
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusInternalServerError)
return
}

cors(w, r)
je := json.NewEncoder(w)
err = je.Encode(ret)
if err != nil {
emsg := fmt.Sprintf("Error: %v", err.Error())
retError(w, emsg, http.StatusBadRequest)
return
}
}

func cors(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
Expand Down Expand Up @@ -558,7 +759,6 @@ func (s *Server) health(w http.ResponseWriter, r *http.Request) {
}
}


func (s *Server) GetRouter() http.Handler {
rtr := mux.NewRouter()

Expand Down Expand Up @@ -608,6 +808,11 @@ func (s *Server) GetRouter() http.Handler {
apiRtr.HandleFunc("/api/v1/spire/entries", s.entryList).Methods("GET")
apiRtr.HandleFunc("/api/v1/spire/entries", s.entryCreate).Methods("POST")
apiRtr.HandleFunc("/api/v1/spire/entries", s.entryDelete).Methods("DELETE")
apiRtr.HandleFunc("/api/v1/spire/bundle", s.bundleGet).Methods("GET")
apiRtr.HandleFunc("/api/v1/spire/federations/bundles", s.federatedBundleList).Methods("GET")
apiRtr.HandleFunc("/api/v1/spire/federations/bundles", s.federatedBundleCreate).Methods("POST")
apiRtr.HandleFunc("/api/v1/spire/federations/bundles", s.federatedBundleUpdate).Methods("PATCH")
apiRtr.HandleFunc("/api/v1/spire/federations/bundles", s.federatedBundleDelete).Methods("DELETE")

// Tornjak specific
apiRtr.HandleFunc("/api/v1/tornjak/serverinfo", s.tornjakGetServerInfo).Methods("GET")
Expand Down Expand Up @@ -681,7 +886,6 @@ func (s *Server) HandleRequests() {
httpsConfig := serverConfig.HTTPSConfig
var tlsConfig *tls.Config


if serverConfig.HTTPSConfig.ListenPort == 0 {
// Fail because this is required field in this section
err = fmt.Errorf("HTTPS Config error: no port configured. Starting insecure HTTP connection at %d...", serverConfig.HTTPConfig.ListenPort)
Expand Down
Loading

0 comments on commit 243788e

Please sign in to comment.