-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #50 from spiffe/feature/policies
YOLO! Introuducing policies
- Loading branch information
Showing
73 changed files
with
2,148 additions
and
396 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// \\ SPIKE: Secure your secrets with SPIFFE. | ||
// \\\\\ Copyright 2024-present SPIKE contributors. | ||
// \\\\\\\ SPDX-License-Identifier: Apache-2.0 | ||
|
||
package policy | ||
|
||
import ( | ||
"errors" | ||
"net/http" | ||
"time" | ||
|
||
state "github.com/spiffe/spike/app/nexus/internal/state/base" | ||
"github.com/spiffe/spike/internal/entity/data" | ||
"github.com/spiffe/spike/internal/entity/v1/reqres" | ||
"github.com/spiffe/spike/internal/log" | ||
"github.com/spiffe/spike/internal/net" | ||
) | ||
|
||
// RoutePutPolicy handles HTTP PUT requests for creating new policies. | ||
// It processes the request body to create a policy with the specified name, | ||
// SPIFFE ID pattern, path pattern, and permissions. | ||
// | ||
// The function expects a JSON request body containing: | ||
// - Name: policy name | ||
// - SpiffeIdPattern: SPIFFE ID matching pattern | ||
// - PathPattern: path matching pattern | ||
// - Permissions: set of allowed permissions | ||
// | ||
// On success, it returns a JSON response with the created policy's ID. | ||
// On failure, it returns an appropriate error response with status code. | ||
// | ||
// Parameters: | ||
// - w: HTTP response writer for sending the response | ||
// - r: HTTP request containing the policy creation data | ||
// - audit: Audit entry for logging the policy creation action | ||
// | ||
// Returns: | ||
// - error: nil on successful policy creation, error otherwise | ||
// | ||
// Example request body: | ||
// | ||
// { | ||
// "name": "example-policy", | ||
// "spiffe_id_pattern": "spiffe://example.org/*/service", | ||
// "path_pattern": "/api/*", | ||
// "permissions": ["read", "write"] | ||
// } | ||
// | ||
// Example success response: | ||
// | ||
// { | ||
// "id": "policy-123" | ||
// } | ||
// | ||
// Example error response: | ||
// | ||
// { | ||
// "err": "Internal server error" | ||
// } | ||
func RoutePutPolicy( | ||
w http.ResponseWriter, r *http.Request, audit *log.AuditEntry, | ||
) error { | ||
log.Log().Info("routePutPolicy", "method", r.Method, "path", r.URL.Path, | ||
"query", r.URL.RawQuery) | ||
audit.Action = log.AuditCreate | ||
|
||
requestBody := net.ReadRequestBody(w, r) | ||
if requestBody == nil { | ||
return errors.New("failed to read request body") | ||
} | ||
|
||
request := net.HandleRequest[ | ||
reqres.PolicyCreateRequest, reqres.PolicyCreateResponse]( | ||
requestBody, w, | ||
reqres.PolicyCreateResponse{Err: reqres.ErrBadInput}, | ||
) | ||
if request == nil { | ||
return errors.New("failed to parse request body") | ||
} | ||
|
||
// TODO: sanitize | ||
|
||
name := request.Name | ||
spiffeIdPattern := request.SpiffeIdPattern | ||
pathPattern := request.PathPattern | ||
permissions := request.Permissions | ||
|
||
policy, err := state.CreatePolicy(data.Policy{ | ||
Id: "", | ||
Name: name, | ||
SpiffeIdPattern: spiffeIdPattern, | ||
PathPattern: pathPattern, | ||
Permissions: permissions, | ||
CreatedAt: time.Time{}, | ||
CreatedBy: "", | ||
}) | ||
if err != nil { | ||
log.Log().Info("routePutPolicy", | ||
"msg", "Failed to create policy", "err", err) | ||
|
||
responseBody := net.MarshalBody(reqres.PolicyCreateResponse{ | ||
Err: "Internal server error", | ||
}, w) | ||
|
||
net.Respond(http.StatusInternalServerError, responseBody, w) | ||
log.Log().Error("routePutPolicy", "msg", "internal server error") | ||
|
||
return err | ||
} | ||
|
||
responseBody := net.MarshalBody(reqres.PolicyCreateResponse{ | ||
Id: policy.Id, | ||
}, w) | ||
|
||
net.Respond(http.StatusOK, responseBody, w) | ||
log.Log().Info("routePutPolicy", "msg", "OK") | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// \\ SPIKE: Secure your secrets with SPIFFE. | ||
// \\\\\ Copyright 2024-present SPIKE contributors. | ||
// \\\\\\\ SPDX-License-Identifier: Apache-2.0 | ||
|
||
package policy | ||
|
||
import ( | ||
"errors" | ||
"net/http" | ||
|
||
state "github.com/spiffe/spike/app/nexus/internal/state/base" | ||
"github.com/spiffe/spike/internal/entity/v1/reqres" | ||
"github.com/spiffe/spike/internal/log" | ||
"github.com/spiffe/spike/internal/net" | ||
) | ||
|
||
// RouteDeletePolicy handles HTTP DELETE requests to remove existing policies. | ||
// It processes the request body to delete a policy specified by its ID. | ||
// | ||
// The function expects a JSON request body containing: | ||
// - Id: unique identifier of the policy to delete | ||
// | ||
// On success, it returns an empty JSON response with HTTP 200 status. | ||
// On failure, it returns an appropriate error response with status code. | ||
// | ||
// Parameters: | ||
// - w: HTTP response writer for sending the response | ||
// - r: HTTP request containing the policy ID to delete | ||
// - audit: Audit entry for logging the policy deletion action | ||
// | ||
// Returns: | ||
// - error: nil on successful policy deletion, error otherwise | ||
// | ||
// Example request body: | ||
// | ||
// { | ||
// "id": "policy-123" | ||
// } | ||
// | ||
// Example success response: | ||
// | ||
// {} | ||
// | ||
// Example error response: | ||
// | ||
// { | ||
// "err": "Internal server error" | ||
// } | ||
// | ||
// Possible errors: | ||
// - Failed to read request body | ||
// - Failed to parse request body | ||
// - Failed to marshal response body | ||
// - Failed to delete policy (internal server error) | ||
func RouteDeletePolicy( | ||
w http.ResponseWriter, r *http.Request, audit *log.AuditEntry, | ||
) error { | ||
log.Log().Info("routeDeletePolicy", "method", r.Method, "path", r.URL.Path, | ||
"query", r.URL.RawQuery) | ||
audit.Action = log.AuditDelete | ||
|
||
requestBody := net.ReadRequestBody(w, r) | ||
if requestBody == nil { | ||
return errors.New("failed to read request body") | ||
} | ||
|
||
request := net.HandleRequest[ | ||
reqres.PolicyDeleteRequest, reqres.PolicyDeleteResponse]( | ||
requestBody, w, | ||
reqres.PolicyDeleteResponse{Err: reqres.ErrBadInput}, | ||
) | ||
if request == nil { | ||
return errors.New("failed to parse request body") | ||
} | ||
|
||
policyId := request.Id | ||
|
||
err := state.DeletePolicy(policyId) | ||
if err != nil { | ||
log.Log().Info("routeDeletePolicy", | ||
"msg", "Failed to delete policy", "err", err) | ||
|
||
responseBody := net.MarshalBody(reqres.PolicyDeleteResponse{ | ||
Err: "Internal server error", | ||
}, w) | ||
if responseBody == nil { | ||
return errors.New("failed to marshal response body") | ||
} | ||
|
||
net.Respond(http.StatusInternalServerError, responseBody, w) | ||
log.Log().Info("routeDeletePolicy", "msg", "internal server error") | ||
return err | ||
} | ||
|
||
responseBody := net.MarshalBody(reqres.PolicyDeleteResponse{}, w) | ||
if responseBody == nil { | ||
return errors.New("failed to marshal response body") | ||
} | ||
|
||
net.Respond(http.StatusOK, responseBody, w) | ||
log.Log().Info("routeDeletePolicy", "msg", "OK") | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// \\ SPIKE: Secure your secrets with SPIFFE. | ||
// \\\\\ Copyright 2024-present SPIKE contributors. | ||
// \\\\\\\ SPDX-License-Identifier: Apache-2.0 | ||
|
||
package policy | ||
|
||
import ( | ||
"errors" | ||
"net/http" | ||
|
||
state "github.com/spiffe/spike/app/nexus/internal/state/base" | ||
"github.com/spiffe/spike/internal/entity/v1/reqres" | ||
"github.com/spiffe/spike/internal/log" | ||
"github.com/spiffe/spike/internal/net" | ||
) | ||
|
||
// RouteListPolicies handles HTTP requests to retrieve all existing policies. | ||
// It returns a list of all policies in the system, including their IDs, names, | ||
// SPIFFE ID patterns, path patterns, and permissions. | ||
// | ||
// The function expects an empty JSON request body ({}) and returns an array | ||
// of policy objects. | ||
// | ||
// Parameters: | ||
// - w: HTTP response writer for sending the response | ||
// - r: HTTP request for the policy listing operation | ||
// - audit: Audit entry for logging the policy list action | ||
// | ||
// Returns: | ||
// - error: nil on successful retrieval, error otherwise | ||
// | ||
// Example request body: | ||
// | ||
// {} | ||
// | ||
// Example success response: | ||
// | ||
// { | ||
// "policies": [ | ||
// { | ||
// "id": "policy-123", | ||
// "name": "example-policy", | ||
// "spiffe_id_pattern": "spiffe://example.org/*/service", | ||
// "path_pattern": "/api/*", | ||
// "permissions": ["read", "write"], | ||
// "created_at": "2024-01-01T00:00:00Z", | ||
// "created_by": "user-abc" | ||
// } | ||
// // ... additional policies | ||
// ] | ||
// } | ||
// | ||
// Example error response: | ||
// | ||
// { | ||
// "err": "Internal server error" | ||
// } | ||
// | ||
// Possible errors: | ||
// - Failed to read request body | ||
// - Failed to parse request body | ||
// - Failed to marshal response body | ||
func RouteListPolicies( | ||
w http.ResponseWriter, r *http.Request, audit *log.AuditEntry, | ||
) error { | ||
log.Log().Info("routeListPolicies", "method", r.Method, "path", r.URL.Path, | ||
"query", r.URL.RawQuery) | ||
audit.Action = log.AuditList | ||
|
||
requestBody := net.ReadRequestBody(w, r) | ||
if requestBody == nil { | ||
return errors.New("failed to read request body") | ||
} | ||
|
||
request := net.HandleRequest[ | ||
reqres.PolicyListRequest, reqres.PolicyListResponse]( | ||
requestBody, w, | ||
reqres.PolicyListResponse{Err: reqres.ErrBadInput}, | ||
) | ||
if request == nil { | ||
return errors.New("failed to parse request body") | ||
} | ||
|
||
policies := state.ListPolicies() | ||
|
||
responseBody := net.MarshalBody(reqres.PolicyListResponse{ | ||
Policies: policies, | ||
}, w) | ||
if responseBody == nil { | ||
return errors.New("failed to marshal response body") | ||
} | ||
|
||
net.Respond(http.StatusOK, responseBody, w) | ||
log.Log().Info("routeListPolicies", "msg", "success") | ||
return nil | ||
} |
Oops, something went wrong.