Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SPIRE Bundle APIs #478

Merged
merged 5 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 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,113 @@ 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
207 changes: 207 additions & 0 deletions api/agent/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,208 @@ 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 @@ -608,6 +810,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
Loading