mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-24 16:17:11 +08:00
Migrate kube_service CRUD endpoints to gRPC (#4792)
The REST endpoints weren't used in any release yet, so we don't need to worry about backwards-compatibility.
This commit is contained in:
@@ -140,11 +140,6 @@ func NewAPIServer(config *APIConfig) http.Handler {
|
||||
srv.DELETE("/:version/tunnelconnections/:cluster/:conn", srv.withAuth(srv.deleteTunnelConnection))
|
||||
srv.DELETE("/:version/tunnelconnections/:cluster", srv.withAuth(srv.deleteTunnelConnections))
|
||||
srv.DELETE("/:version/tunnelconnections", srv.withAuth(srv.deleteAllTunnelConnections))
|
||||
// TODO(awly): migrate these to the gRPC service.
|
||||
srv.POST("/:version/kube_services", srv.withAuth(srv.upsertKubeService))
|
||||
srv.GET("/:version/kube_services", srv.withAuth(srv.getKubeServices))
|
||||
srv.DELETE("/:version/kube_services/:name", srv.withAuth(srv.deleteKubeService))
|
||||
srv.DELETE("/:version/kube_services", srv.withAuth(srv.deleteAllKubeServices))
|
||||
|
||||
// Server Credentials
|
||||
srv.POST("/:version/server/credentials", srv.withAuth(srv.generateServerKeys))
|
||||
@@ -340,8 +335,6 @@ func (s *APIServer) upsertServer(auth services.Presence, role teleport.Role, r *
|
||||
kind = services.KindAuthServer
|
||||
case teleport.RoleProxy:
|
||||
kind = services.KindProxy
|
||||
case teleport.RoleKube:
|
||||
kind = services.KindKubeService
|
||||
default:
|
||||
return nil, trace.BadParameter("upsertServer with unknown role: %q", role)
|
||||
}
|
||||
@@ -375,10 +368,6 @@ func (s *APIServer) upsertServer(auth services.Presence, role teleport.Role, r *
|
||||
if err := auth.UpsertProxy(server); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
case teleport.RoleKube:
|
||||
if err := auth.UpsertKubeService(r.Context(), server); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
default:
|
||||
return nil, trace.BadParameter("unknown server role %q", role)
|
||||
}
|
||||
@@ -2497,36 +2486,6 @@ func (s *APIServer) getServerID(r *http.Request) (string, error) {
|
||||
return strings.TrimSuffix(role.Username, "."+clusterName), nil
|
||||
}
|
||||
|
||||
func (s *APIServer) upsertKubeService(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) {
|
||||
return s.upsertServer(auth, teleport.RoleKube, r, p)
|
||||
}
|
||||
|
||||
func (s *APIServer) getKubeServices(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) {
|
||||
servers, err := auth.GetKubeServices(r.Context())
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return marshalServers(servers, version)
|
||||
}
|
||||
|
||||
func (s *APIServer) deleteKubeService(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) {
|
||||
name := p.ByName("name")
|
||||
if name == "" {
|
||||
return nil, trace.BadParameter("missing kubernetes service name")
|
||||
}
|
||||
if err := auth.DeleteKubeService(r.Context(), name); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return message("ok"), nil
|
||||
}
|
||||
|
||||
func (s *APIServer) deleteAllKubeServices(auth ClientI, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) {
|
||||
if err := auth.DeleteAllKubeServices(r.Context()); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return message("ok"), nil
|
||||
}
|
||||
|
||||
func message(msg string) map[string]interface{} {
|
||||
return map[string]interface{}{"message": msg}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package auth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -35,7 +34,6 @@ import (
|
||||
|
||||
func TestUpsertServer(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.TODO()
|
||||
const remoteAddr = "request-remote-addr"
|
||||
|
||||
tests := []struct {
|
||||
@@ -90,21 +88,6 @@ func TestUpsertServer(t *testing.T) {
|
||||
},
|
||||
assertErr: require.NoError,
|
||||
},
|
||||
{
|
||||
desc: "kubernetes",
|
||||
reqServer: &services.ServerV2{
|
||||
Metadata: services.Metadata{Name: "test-server", Namespace: defaults.Namespace},
|
||||
Version: services.V2,
|
||||
Kind: services.KindKubeService,
|
||||
},
|
||||
role: teleport.RoleKube,
|
||||
wantServer: &services.ServerV2{
|
||||
Metadata: services.Metadata{Name: "test-server", Namespace: defaults.Namespace},
|
||||
Version: services.V2,
|
||||
Kind: services.KindKubeService,
|
||||
},
|
||||
assertErr: require.NoError,
|
||||
},
|
||||
{
|
||||
desc: "unknown",
|
||||
reqServer: &services.ServerV2{
|
||||
@@ -146,7 +129,6 @@ func TestUpsertServer(t *testing.T) {
|
||||
addServers(s.GetAuthServers())
|
||||
addServers(s.GetNodes(defaults.Namespace))
|
||||
addServers(s.GetProxies())
|
||||
addServers(s.GetKubeServices(ctx))
|
||||
require.Empty(t, cmp.Diff(allServers, []services.Server{tt.wantServer}))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -870,19 +870,17 @@ func (a *ServerWithRoles) Ping(ctx context.Context) (proto.PingResponse, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
type contextKey string
|
||||
|
||||
// WithDelegator creates a child context with the AccessRequestDelegator
|
||||
// value set. Optionally used by AuthServer.SetAccessRequestState to log
|
||||
// a delegating identity.
|
||||
func WithDelegator(ctx context.Context, delegator string) context.Context {
|
||||
return context.WithValue(ctx, contextKey(events.AccessRequestDelegator), delegator)
|
||||
return context.WithValue(ctx, ContextDelegator, delegator)
|
||||
}
|
||||
|
||||
// getDelegator attempts to load the context value AccessRequestDelegator,
|
||||
// returning the empty string if no value was found.
|
||||
func getDelegator(ctx context.Context) string {
|
||||
delegator, ok := ctx.Value(contextKey(events.AccessRequestDelegator)).(string)
|
||||
delegator, ok := ctx.Value(ContextDelegator).(string)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
+27
-17
@@ -2952,37 +2952,37 @@ func (c *Client) DeleteSemaphore(ctx context.Context, filter services.SemaphoreF
|
||||
// UpsertKubeService is used by kubernetes services to report their presence
|
||||
// to other auth servers in form of hearbeat expiring after ttl period.
|
||||
func (c *Client) UpsertKubeService(ctx context.Context, s services.Server) error {
|
||||
data, err := services.GetServerMarshaler().MarshalServer(s)
|
||||
clt, err := c.grpc()
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
args := &upsertServerRawReq{
|
||||
Server: data,
|
||||
server, ok := s.(*services.ServerV2)
|
||||
if !ok {
|
||||
return trace.BadParameter("invalid type %T, expected *services.ServerV2", server)
|
||||
}
|
||||
_, err = c.PostJSON(c.Endpoint("kube_services"), args)
|
||||
_, err = clt.UpsertKubeService(ctx, &proto.UpsertKubeServiceRequest{
|
||||
Server: server,
|
||||
})
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// GetKubeServices returns the list of kubernetes services registered in the
|
||||
// cluster.
|
||||
func (c *Client) GetKubeServices(ctx context.Context) ([]services.Server, error) {
|
||||
out, err := c.Get(c.Endpoint("kube_services"), url.Values{})
|
||||
clt, err := c.grpc()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
var items []json.RawMessage
|
||||
if err := json.Unmarshal(out.Bytes(), &items); err != nil {
|
||||
resp, err := clt.GetKubeServices(ctx, &proto.GetKubeServicesRequest{})
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
re := make([]services.Server, len(items))
|
||||
for i, raw := range items {
|
||||
server, err := services.GetServerMarshaler().UnmarshalServer(raw, services.KindKubeService, services.SkipValidation())
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
re[i] = server
|
||||
|
||||
var servers []services.Server
|
||||
for _, server := range resp.GetServers() {
|
||||
servers = append(servers, server)
|
||||
}
|
||||
return re, nil
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// GetAppServers gets all application servers.
|
||||
@@ -3184,13 +3184,23 @@ func (c *Client) GenerateAppToken(ctx context.Context, req jwt.GenerateAppTokenR
|
||||
|
||||
// DeleteKubeService deletes a named kubernetes service.
|
||||
func (c *Client) DeleteKubeService(ctx context.Context, name string) error {
|
||||
_, err := c.Delete(c.Endpoint("kube_services", name))
|
||||
clt, err := c.grpc()
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
_, err = clt.DeleteKubeService(ctx, &proto.DeleteKubeServiceRequest{
|
||||
Name: name,
|
||||
})
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// DeleteAllKubeServices deletes all registered kubernetes services.
|
||||
func (c *Client) DeleteAllKubeServices(ctx context.Context) error {
|
||||
_, err := c.Delete(c.Endpoint("kube_services"))
|
||||
clt, err := c.grpc()
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
_, err = clt.DeleteAllKubeServices(ctx, &proto.DeleteAllKubeServicesRequest{})
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/teleport"
|
||||
@@ -37,8 +38,10 @@ import (
|
||||
"github.com/gravitational/trace/trail"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"google.golang.org/grpc/peer"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
// Register gzip compressor for gRPC.
|
||||
_ "google.golang.org/grpc/encoding/gzip"
|
||||
@@ -861,6 +864,89 @@ func (g *GRPCServer) UpdateRemoteCluster(ctx context.Context, req *services.Remo
|
||||
return &empty.Empty{}, nil
|
||||
}
|
||||
|
||||
// GetKubeServices gets all kubernetes services.
|
||||
func (g *GRPCServer) GetKubeServices(ctx context.Context, req *proto.GetKubeServicesRequest) (*proto.GetKubeServicesResponse, error) {
|
||||
auth, err := g.authenticate(ctx)
|
||||
if err != nil {
|
||||
return nil, trail.ToGRPC(err)
|
||||
}
|
||||
|
||||
kubeServices, err := auth.GetKubeServices(ctx)
|
||||
if err != nil {
|
||||
return nil, trail.ToGRPC(err)
|
||||
}
|
||||
|
||||
var servers []*services.ServerV2
|
||||
for _, s := range kubeServices {
|
||||
server, ok := s.(*services.ServerV2)
|
||||
if !ok {
|
||||
return nil, trail.ToGRPC(trace.BadParameter("unexpected type %T", s))
|
||||
}
|
||||
servers = append(servers, server)
|
||||
}
|
||||
|
||||
return &proto.GetKubeServicesResponse{
|
||||
Servers: servers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpsertKubeService adds a kubernetes service.
|
||||
func (g *GRPCServer) UpsertKubeService(ctx context.Context, req *proto.UpsertKubeServiceRequest) (*empty.Empty, error) {
|
||||
auth, err := g.authenticate(ctx)
|
||||
if err != nil {
|
||||
return nil, trail.ToGRPC(err)
|
||||
}
|
||||
|
||||
server := req.GetServer()
|
||||
// If Addr in the server is localhost, replace it with the address we see
|
||||
// from our end.
|
||||
//
|
||||
// Services that listen on "0.0.0.0:12345" will put that exact address in
|
||||
// the server.Addr field. It's not useful for other services that want to
|
||||
// connect to it (like a proxy). Remote address of the gRPC connection is
|
||||
// the closest thing we have to a public IP for the service.
|
||||
clientAddr, ok := ctx.Value(ContextClientAddr).(net.Addr)
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "bug: client address not found in request context")
|
||||
}
|
||||
server.SetAddr(utils.ReplaceLocalhost(server.GetAddr(), clientAddr.String()))
|
||||
|
||||
if err := auth.UpsertKubeService(ctx, server); err != nil {
|
||||
return nil, trail.ToGRPC(err)
|
||||
}
|
||||
return new(empty.Empty), nil
|
||||
}
|
||||
|
||||
// DeleteKubeService removes a kubernetes service.
|
||||
func (g *GRPCServer) DeleteKubeService(ctx context.Context, req *proto.DeleteKubeServiceRequest) (*empty.Empty, error) {
|
||||
auth, err := g.authenticate(ctx)
|
||||
if err != nil {
|
||||
return nil, trail.ToGRPC(err)
|
||||
}
|
||||
|
||||
err = auth.DeleteKubeService(ctx, req.GetName())
|
||||
if err != nil {
|
||||
return nil, trail.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &empty.Empty{}, nil
|
||||
}
|
||||
|
||||
// DeleteAllKubeServices removes all kubernetes services.
|
||||
func (g *GRPCServer) DeleteAllKubeServices(ctx context.Context, req *proto.DeleteAllKubeServicesRequest) (*empty.Empty, error) {
|
||||
auth, err := g.authenticate(ctx)
|
||||
if err != nil {
|
||||
return nil, trail.ToGRPC(err)
|
||||
}
|
||||
|
||||
err = auth.DeleteAllKubeServices(ctx)
|
||||
if err != nil {
|
||||
return nil, trail.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &empty.Empty{}, nil
|
||||
}
|
||||
|
||||
type grpcContext struct {
|
||||
*Context
|
||||
*ServerWithRoles
|
||||
|
||||
@@ -330,6 +330,7 @@ func (a *Middleware) UnaryInterceptor(ctx context.Context, req interface{}, info
|
||||
return nil, trail.ToGRPC(trace.LimitExceeded("connection limit exceeded"))
|
||||
}
|
||||
defer a.Limiter.ConnLimiter.Release(clientIP, 1)
|
||||
ctx = context.WithValue(ctx, ContextClientAddr, peerInfo.Addr)
|
||||
|
||||
tlsInfo, ok := peerInfo.AuthInfo.(credentials.TLSInfo)
|
||||
if !ok {
|
||||
|
||||
+11
-3
@@ -22,6 +22,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gravitational/teleport"
|
||||
"github.com/gravitational/teleport/lib/events"
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
"github.com/gravitational/teleport/lib/tlsca"
|
||||
|
||||
@@ -517,10 +518,17 @@ func contextForLocalUser(u LocalUser, identity services.UserGetter, access servi
|
||||
}, nil
|
||||
}
|
||||
|
||||
type contextUserKey string
|
||||
type contextKey string
|
||||
|
||||
// ContextUser is a user set in the context of the request
|
||||
const ContextUser contextUserKey = "teleport-user"
|
||||
const (
|
||||
// ContextUser is a user set in the context of the request
|
||||
ContextUser contextKey = "teleport-user"
|
||||
// ContextClientAddr is a client address set in the context of the request
|
||||
ContextClientAddr contextKey = "client-addr"
|
||||
// ContextDelegator is a delegator for access requests set in the context
|
||||
// of the request
|
||||
ContextDelegator contextKey = events.AccessRequestDelegator
|
||||
)
|
||||
|
||||
// clientUsername returns the username of a remote HTTP client making the call.
|
||||
// If ctx didn't pass through auth middleware or did not come from an HTTP
|
||||
|
||||
+1177
-216
File diff suppressed because it is too large
Load Diff
@@ -367,6 +367,32 @@ message CreateAppSessionResponse {
|
||||
// DeleteAppSessionRequest contains the parameters used to remove an application web session.
|
||||
message DeleteAppSessionRequest { string SessionID = 1 [ (gogoproto.jsontag) = "session_id" ]; }
|
||||
|
||||
// GetKubeServicesRequest are the parameters used to request kubernetes services.
|
||||
message GetKubeServicesRequest {
|
||||
}
|
||||
|
||||
// GetKubeServicesResponse contains all requested kubernetes services.
|
||||
message GetKubeServicesResponse {
|
||||
// Servers is a slice of services.Server that represent kubernetes
|
||||
// services.
|
||||
repeated services.ServerV2 Servers = 1 [ (gogoproto.jsontag) = "servers" ];
|
||||
}
|
||||
|
||||
// UpsertKubeServiceRequest are the parameters used to add or update a
|
||||
// kubernetes service.
|
||||
message UpsertKubeServiceRequest {
|
||||
services.ServerV2 Server = 1 [ (gogoproto.jsontag) = "server" ];
|
||||
}
|
||||
|
||||
// DeleteKubeServiceRequest are the parameters used to remove a kubernetes service.
|
||||
message DeleteKubeServiceRequest {
|
||||
// Name is the name of the kubernetes service to delete.
|
||||
string Name = 2 [ (gogoproto.jsontag) = "name" ];
|
||||
}
|
||||
|
||||
// DeleteAllKubeServicesRequest are the parameters used to remove all kubernetes services.
|
||||
message DeleteAllKubeServicesRequest {}
|
||||
|
||||
// AuthService is authentication/authorization service implementation
|
||||
service AuthService {
|
||||
// SendKeepAlives allows node to send a stream of keep alive requests
|
||||
@@ -455,4 +481,13 @@ service AuthService {
|
||||
|
||||
// UpdateRemoteCluster updates remote cluster
|
||||
rpc UpdateRemoteCluster(services.RemoteClusterV3) returns (google.protobuf.Empty);
|
||||
|
||||
// GetKubeServices gets all kubernetes services.
|
||||
rpc GetKubeServices(GetKubeServicesRequest) returns (GetKubeServicesResponse);
|
||||
// UpsertKubeService adds or updates a kubernetes service.
|
||||
rpc UpsertKubeService(UpsertKubeServiceRequest) returns (google.protobuf.Empty);
|
||||
// DeleteKubeService removes a kubernetes service.
|
||||
rpc DeleteKubeService(DeleteKubeServiceRequest) returns (google.protobuf.Empty);
|
||||
// DeleteAllKubeServices removes all kubernetes services.
|
||||
rpc DeleteAllKubeServices(DeleteAllKubeServicesRequest) returns (google.protobuf.Empty);
|
||||
}
|
||||
|
||||
@@ -1018,6 +1018,9 @@ func (s *PresenceService) GetKubeServices(ctx context.Context) ([]services.Serve
|
||||
|
||||
// DeleteKubeService deletes a named kubernetes service.
|
||||
func (s *PresenceService) DeleteKubeService(ctx context.Context, name string) error {
|
||||
if name == "" {
|
||||
return trace.BadParameter("no name specified for kubernetes service deletion")
|
||||
}
|
||||
return trace.Wrap(s.Delete(ctx, backend.Key(kubeServicesPrefix, name)))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user