Skip to content

Commit

Permalink
Migrate ReverseTunnel Resource APIs from HTTP to gRPC (#46761)
Browse files Browse the repository at this point in the history
* Start hacking on migrating reversetunnel

* Migrate ReverseTunnel HTTP API to gRPC

* Wire Cache into Presence GRPC service

* Add TestPresenceService_ListReverseTunnels

* Add UpsertReverseTunnelV2 store method which returns upserted resource

* Make API client return reversetunnel on upsert

* Add TestListReverseTunnels

* Add TestDeleteReverseTunnel

* Add TestUpsertReverseTunnel

* Missing err check

* Remove presenceService from gRPCServer struct

* Add deprecations on GetReverseTunnels
  • Loading branch information
strideynet authored Oct 2, 2024
1 parent 8986887 commit 8a85342
Show file tree
Hide file tree
Showing 28 changed files with 1,425 additions and 232 deletions.
39 changes: 39 additions & 0 deletions api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5084,6 +5084,45 @@ func (c *Client) GetRemoteCluster(ctx context.Context, name string) (types.Remot
return rc, trace.Wrap(err)
}

// ListReverseTunnels returns a page of remote clusters.
func (c *Client) ListReverseTunnels(ctx context.Context, pageSize int, nextToken string) ([]types.ReverseTunnel, string, error) {
res, err := c.PresenceServiceClient().ListReverseTunnels(ctx, &presencepb.ListReverseTunnelsRequest{
PageSize: int32(pageSize),
PageToken: nextToken,
})
if err != nil {
return nil, "", trace.Wrap(err)
}
rcs := make([]types.ReverseTunnel, 0, len(res.ReverseTunnels))
for _, rc := range res.ReverseTunnels {
rcs = append(rcs, rc)
}
return rcs, res.NextPageToken, nil
}

// DeleteReverseTunnel deletes a reverse tunnel resource
func (c *Client) DeleteReverseTunnel(ctx context.Context, name string) error {
_, err := c.PresenceServiceClient().DeleteReverseTunnel(ctx, &presencepb.DeleteReverseTunnelRequest{
Name: name,
})
return trace.Wrap(err)
}

// UpsertReverseTunnel creates or updates reverse tunnel resource
func (c *Client) UpsertReverseTunnel(ctx context.Context, rt types.ReverseTunnel) (types.ReverseTunnel, error) {
rtV3, ok := rt.(*types.ReverseTunnelV2)
if !ok {
return nil, trace.BadParameter("unsupported reverse tunnel type %T", rt)
}
res, err := c.PresenceServiceClient().UpsertReverseTunnel(ctx, &presencepb.UpsertReverseTunnelRequest{
ReverseTunnel: rtV3,
})
if err != nil {
return nil, trace.Wrap(err)
}
return res, nil
}

// GetRemoteClusters returns all remote clusters.
// Deprecated: use ListRemoteClusters instead.
func (c *Client) GetRemoteClusters(ctx context.Context) ([]types.RemoteCluster, error) {
Expand Down
378 changes: 349 additions & 29 deletions api/gen/proto/go/teleport/presence/v1/service.pb.go

Large diffs are not rendered by default.

120 changes: 120 additions & 0 deletions api/gen/proto/go/teleport/presence/v1/service_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions api/proto/teleport/presence/v1/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ service PresenceService {
rpc UpdateRemoteCluster(UpdateRemoteClusterRequest) returns (types.RemoteClusterV3);
// DeleteRemoteCluster removes an existing RemoteCluster by name.
rpc DeleteRemoteCluster(DeleteRemoteClusterRequest) returns (google.protobuf.Empty);

// ListReverseTunnels retrieves a page of ReverseTunnels.
rpc ListReverseTunnels(ListReverseTunnelsRequest) returns (ListReverseTunnelsResponse);
// UpsertReverseTunnel upserts a ReverseTunnel.
rpc UpsertReverseTunnel(UpsertReverseTunnelRequest) returns (types.ReverseTunnelV2);
// DeleteReverseTunnel removes an existing ReverseTunnel by name.
rpc DeleteReverseTunnel(DeleteReverseTunnelRequest) returns (google.protobuf.Empty);
}

// Request for GetRemoteCluster
Expand Down Expand Up @@ -75,3 +82,36 @@ message DeleteRemoteClusterRequest {
// Name is the name of the RemoteCluster to delete.
string name = 1;
}

// Request for ListReverseTunnels
message ListReverseTunnelsRequest {
// The maximum number of items to return.
// The server may impose a different page size at its discretion.
int32 page_size = 1;

// The page_token is the next_page_token value returned from a previous List
// request, if any.
string page_token = 2;
}

// Response for ListReverseTunnels
message ListReverseTunnelsResponse {
// ReverseTunnels is the list of ReverseTunnels that were retrieved.
repeated types.ReverseTunnelV2 reverse_tunnels = 1;

// Token to retrieve the next page of results, or empty if there are no
// more results in the list.
string next_page_token = 2;
}

// Request for UpsertReverseTunnel
message UpsertReverseTunnelRequest {
// ReverseTunnel is the ReverseTunnel to upsert.
types.ReverseTunnelV2 reverse_tunnel = 1;
}

// Request for DeleteReverseTunnel
message DeleteReverseTunnelRequest {
// Name is the name of the ReverseTunnel to delete.
string name = 1;
}
8 changes: 6 additions & 2 deletions lib/auth/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ func NewAPIServer(config *APIConfig) (http.Handler, error) {
srv.DELETE("/:version/tunnelconnections", srv.WithAuth(srv.deleteAllTunnelConnections))

// Reverse tunnels
// TODO(noah): DELETE IN 18.0.0 - all these methods are now gRPC.
srv.POST("/:version/reversetunnels", srv.WithAuth(srv.upsertReverseTunnel))
srv.GET("/:version/reversetunnels", srv.WithAuth(srv.getReverseTunnels))
srv.DELETE("/:version/reversetunnels/:domain", srv.WithAuth(srv.deleteReverseTunnel))
Expand Down Expand Up @@ -344,6 +345,7 @@ type upsertReverseTunnelRawReq struct {
}

// upsertReverseTunnel is called by admin to create a reverse tunnel to remote proxy
// TODO(noah): DELETE IN 18.0.0 - all these methods are now gRPC.
func (s *APIServer) upsertReverseTunnel(auth *ServerWithRoles, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) {
var req upsertReverseTunnelRawReq
if err := httplib.ReadJSON(r, &req); err != nil {
Expand All @@ -359,13 +361,14 @@ func (s *APIServer) upsertReverseTunnel(auth *ServerWithRoles, w http.ResponseWr
if req.TTL != 0 {
tun.SetExpiry(s.Now().UTC().Add(req.TTL))
}
if err := auth.UpsertReverseTunnel(tun); err != nil {
if err := auth.UpsertReverseTunnel(r.Context(), tun); err != nil {
return nil, trace.Wrap(err)
}
return message("ok"), nil
}

// getReverseTunnels returns a list of reverse tunnels
// TODO(noah): DELETE IN 18.0.0 - all these methods are now gRPC.
func (s *APIServer) getReverseTunnels(auth *ServerWithRoles, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) {
reverseTunnels, err := auth.GetReverseTunnels(r.Context())
if err != nil {
Expand All @@ -383,9 +386,10 @@ func (s *APIServer) getReverseTunnels(auth *ServerWithRoles, w http.ResponseWrit
}

// deleteReverseTunnel deletes reverse tunnel
// TODO(noah): DELETE IN 18.0.0 - all these methods are now gRPC.
func (s *APIServer) deleteReverseTunnel(auth *ServerWithRoles, w http.ResponseWriter, r *http.Request, p httprouter.Params, version string) (interface{}, error) {
domainName := p.ByName("domain")
err := auth.DeleteReverseTunnel(domainName)
err := auth.DeleteReverseTunnel(r.Context(), domainName)
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
2 changes: 1 addition & 1 deletion lib/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,7 @@ func TestTrustedClusterCRUDEventEmitted(t *testing.T) {
require.NoError(t, s.a.UpsertCertAuthority(ctx, suite.NewTestCA(types.UserCA, "test")))
require.NoError(t, s.a.UpsertCertAuthority(ctx, suite.NewTestCA(types.HostCA, "test")))

err = s.a.createReverseTunnel(tc)
err = s.a.createReverseTunnel(ctx, tc)
require.NoError(t, err)

// test create event for switch case: when tc exists but enabled is false
Expand Down
20 changes: 8 additions & 12 deletions lib/auth/auth_with_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -2131,32 +2131,28 @@ func (a *ServerWithRoles) DeleteProxy(ctx context.Context, name string) error {
return a.authServer.DeleteProxy(ctx, name)
}

func (a *ServerWithRoles) UpsertReverseTunnel(r types.ReverseTunnel) error {
// TODO(noah): DELETE IN 18.0.0 - all these methods are now gRPC.
func (a *ServerWithRoles) UpsertReverseTunnel(ctx context.Context, r types.ReverseTunnel) error {
if err := a.action(apidefaults.Namespace, types.KindReverseTunnel, types.VerbCreate, types.VerbUpdate); err != nil {
return trace.Wrap(err)
}
return a.authServer.UpsertReverseTunnel(r)
}

func (a *ServerWithRoles) GetReverseTunnel(name string, opts ...services.MarshalOption) (types.ReverseTunnel, error) {
if err := a.action(apidefaults.Namespace, types.KindReverseTunnel, types.VerbRead); err != nil {
return nil, trace.Wrap(err)
}
return a.authServer.GetReverseTunnel(name, opts...)
return a.authServer.UpsertReverseTunnel(ctx, r)
}

// TODO(noah): DELETE IN 18.0.0 - all these methods are now gRPC.
func (a *ServerWithRoles) GetReverseTunnels(ctx context.Context, opts ...services.MarshalOption) ([]types.ReverseTunnel, error) {
if err := a.action(apidefaults.Namespace, types.KindReverseTunnel, types.VerbList, types.VerbRead); err != nil {
return nil, trace.Wrap(err)
}
return a.authServer.GetReverseTunnels(ctx, opts...)
return a.authServer.GetReverseTunnels(ctx)
}

func (a *ServerWithRoles) DeleteReverseTunnel(domainName string) error {
// TODO(noah): DELETE IN 18.0.0 - all these methods are now gRPC.
func (a *ServerWithRoles) DeleteReverseTunnel(ctx context.Context, domainName string) error {
if err := a.action(apidefaults.Namespace, types.KindReverseTunnel, types.VerbDelete); err != nil {
return trace.Wrap(err)
}
return a.authServer.DeleteReverseTunnel(domainName)
return a.authServer.DeleteReverseTunnel(ctx, domainName)
}

func (a *ServerWithRoles) DeleteToken(ctx context.Context, token string) error {
Expand Down
9 changes: 6 additions & 3 deletions lib/auth/authclient/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ type ReadProxyAccessPoint interface {
GetAuthServers() ([]types.Server, error)

// GetReverseTunnels returns a list of reverse tunnels
GetReverseTunnels(ctx context.Context, opts ...services.MarshalOption) ([]types.ReverseTunnel, error)
GetReverseTunnels(ctx context.Context) ([]types.ReverseTunnel, error)

// GetAllTunnelConnections returns all tunnel connections
GetAllTunnelConnections(opts ...services.MarshalOption) ([]types.TunnelConnection, error)
Expand Down Expand Up @@ -391,7 +391,7 @@ type ReadRemoteProxyAccessPoint interface {
GetAuthServers() ([]types.Server, error)

// GetReverseTunnels returns a list of reverse tunnels
GetReverseTunnels(ctx context.Context, opts ...services.MarshalOption) ([]types.ReverseTunnel, error)
GetReverseTunnels(ctx context.Context) ([]types.ReverseTunnel, error)

// GetAllTunnelConnections returns all tunnel connections
GetAllTunnelConnections(opts ...services.MarshalOption) ([]types.TunnelConnection, error)
Expand Down Expand Up @@ -953,7 +953,10 @@ type Cache interface {
NewWatcher(ctx context.Context, watch types.Watch) (types.Watcher, error)

// GetReverseTunnels returns a list of reverse tunnels
GetReverseTunnels(ctx context.Context, opts ...services.MarshalOption) ([]types.ReverseTunnel, error)
GetReverseTunnels(ctx context.Context) ([]types.ReverseTunnel, error)

// ListReverseTunnels returns a paginated list of reverse tunnels.
ListReverseTunnels(ctx context.Context, pageSize int, pageToken string) ([]types.ReverseTunnel, string, error)

// GetClusterName returns cluster name
GetClusterName(opts ...services.MarshalOption) (types.ClusterName, error)
Expand Down
Loading

0 comments on commit 8a85342

Please sign in to comment.