Skip to content

Commit

Permalink
Merge branch 'master' into tcsc/provisioning-locks
Browse files Browse the repository at this point in the history
  • Loading branch information
tcsc authored Oct 23, 2024
2 parents 16db65d + d82ee84 commit 0c9090d
Show file tree
Hide file tree
Showing 73 changed files with 4,070 additions and 897 deletions.
93 changes: 93 additions & 0 deletions .github/ISSUE_TEMPLATE/webtestplan.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,99 @@ spec:
- [ ] Verify that root is marked with a `root` pill
- [ ] Verify that cluster dropdown menu items goes to the correct route

## Application Access

### Required Applications

Create two apps running locally, a frontend app and a backend app. The frontend app should
make an API request to the backend app at its teleport public_addr

<details>
<summary>You can use this example app if you don't have a frontend/backend setup</summary>

```go
package main

import (
"encoding/json"
"fmt"
"log"
"net/http"
)

// change to your cluster addr
const clusterName = "avatus.sh"

func main() {
// handler for the html page. this is the "client".
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
html := fmt.Sprintf(html, clusterName)
w.Header().Set("Content-Type", "text/html")
w.Write([]byte(html))
})

// Handler for the API endpoint
http.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", fmt.Sprintf("https://client.%s", clusterName))
w.Header().Set("Access-Control-Allow-Credentials", "true")
data := map[string]string{"hello": "world"}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
})

log.Println("Server starting on http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}

const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>API Data Fetcher</title>
</head>
<body>
<div id="result"></div>
<div id="cors-result"></div>
<script>
fetch('https://api.%s/api/data', { credentials: 'include' })
.then(response => response.json())
.then(data => {
document.getElementById('result').textContent = JSON.stringify(data);
})
.catch(error => console.error('Error:', error));
</script>
</body>
</html>
`
```
</details>

Update your app service to serve the apps like this (update your public addr to what makes sense for your cluster)
```
app_service:
enabled: "yes"
debug_app: true
apps:
- name: client
uri: http://localhost:8080
public_addr: client.avatus.sh
required_apps:
- api
- name: api
uri: http://localhost:8080
public_addr: api.avatus.sh
cors:
allowed_origins:
- https://client.avatus.sh
```

Launch your cluster and make sure you are logged out of your api by going to `https://api.avatus.sh/teleport-logout`

- [ ] Launch the client app and you should see `{"hello":"world"}` response
- [ ] You should see no CORS issues in the console

## Access Requests

Not available for OSS
Expand Down
6 changes: 6 additions & 0 deletions api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import (
"github.com/gravitational/teleport/api/client/accessmonitoringrules"
crownjewelapi "github.com/gravitational/teleport/api/client/crownjewel"
"github.com/gravitational/teleport/api/client/discoveryconfig"
"github.com/gravitational/teleport/api/client/dynamicwindows"
"github.com/gravitational/teleport/api/client/externalauditstorage"
kubewaitingcontainerclient "github.com/gravitational/teleport/api/client/kubewaitingcontainer"
"github.com/gravitational/teleport/api/client/okta"
Expand All @@ -74,6 +75,7 @@ import (
dbobjectimportrulev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobjectimportrule/v1"
devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1"
discoveryconfigv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/discoveryconfig/v1"
dynamicwindowsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dynamicwindows/v1"
externalauditstoragev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/externalauditstorage/v1"
integrationpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1"
kubeproto "github.com/gravitational/teleport/api/gen/proto/go/teleport/kube/v1"
Expand Down Expand Up @@ -2657,6 +2659,10 @@ func (c *Client) SearchSessionEvents(ctx context.Context, fromUTC time.Time, toU
return decodedEvents, response.LastKey, nil
}

func (c *Client) DynamicDesktopClient() *dynamicwindows.Client {
return dynamicwindows.NewClient(dynamicwindowsv1.NewDynamicWindowsServiceClient(c.conn))
}

// ClusterConfigClient returns an unadorned Cluster Configuration client, using the underlying
// Auth gRPC connection.
func (c *Client) ClusterConfigClient() clusterconfigpb.ClusterConfigServiceClient {
Expand Down
93 changes: 93 additions & 0 deletions api/client/dynamicwindows/dynamicwindows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package dynamicwindows

import (
"context"

"github.com/gravitational/trace"

dynamicwindows "github.com/gravitational/teleport/api/gen/proto/go/teleport/dynamicwindows/v1"
"github.com/gravitational/teleport/api/types"
)

// Client is a DynamicWindowsDesktop client.
type Client struct {
grpcClient dynamicwindows.DynamicWindowsServiceClient
}

// NewClient creates a new StaticHostUser client.
func NewClient(grpcClient dynamicwindows.DynamicWindowsServiceClient) *Client {
return &Client{
grpcClient: grpcClient,
}
}

func (c *Client) GetDynamicWindowsDesktop(ctx context.Context, name string) (types.DynamicWindowsDesktop, error) {
desktop, err := c.grpcClient.GetDynamicWindowsDesktop(ctx, &dynamicwindows.GetDynamicWindowsDesktopRequest{
Name: name,
})
return desktop, trace.Wrap(err)
}

func (c *Client) ListDynamicWindowsDesktop(ctx context.Context, pageSize int, pageToken string) ([]types.DynamicWindowsDesktop, string, error) {
resp, err := c.grpcClient.ListDynamicWindowsDesktops(ctx, &dynamicwindows.ListDynamicWindowsDesktopsRequest{
PageSize: int32(pageSize),
PageToken: pageToken,
})
if err != nil {
return nil, "", trace.Wrap(err)
}
desktops := make([]types.DynamicWindowsDesktop, 0, len(resp.GetDesktops()))
for _, desktop := range resp.GetDesktops() {
desktops = append(desktops, desktop)
}
return desktops, resp.GetNextPageToken(), nil
}

func (c *Client) CreateDynamicWindowsDesktop(ctx context.Context, desktop types.DynamicWindowsDesktop) (types.DynamicWindowsDesktop, error) {
switch desktop := desktop.(type) {
case *types.DynamicWindowsDesktopV1:
desktop, err := c.grpcClient.CreateDynamicWindowsDesktop(ctx, &dynamicwindows.CreateDynamicWindowsDesktopRequest{
Desktop: desktop,
})
return desktop, trace.Wrap(err)
default:
return nil, trace.BadParameter("unknown desktop type: %T", desktop)
}
}

func (c *Client) UpdateDynamicWindowsDesktop(ctx context.Context, desktop types.DynamicWindowsDesktop) (types.DynamicWindowsDesktop, error) {
switch desktop := desktop.(type) {
case *types.DynamicWindowsDesktopV1:
desktop, err := c.grpcClient.UpdateDynamicWindowsDesktop(ctx, &dynamicwindows.UpdateDynamicWindowsDesktopRequest{
Desktop: desktop,
})
return desktop, trace.Wrap(err)
default:
return nil, trace.BadParameter("unknown desktop type: %T", desktop)
}
}

func (c *Client) DeleteDynamicWindowsDesktop(ctx context.Context, name string) error {
_, err := c.grpcClient.DeleteDynamicWindowsDesktop(ctx, &dynamicwindows.DeleteDynamicWindowsDesktopRequest{
Name: name,
})
return trace.Wrap(err)
}
7 changes: 7 additions & 0 deletions api/client/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ func EventToGRPC(in types.Event) (*proto.Event, error) {
out.Resource = &proto.Event_WindowsDesktop{
WindowsDesktop: r,
}
case *types.DynamicWindowsDesktopV1:
out.Resource = &proto.Event_DynamicWindowsDesktop{
DynamicWindowsDesktop: r,
}
case *types.InstallerV1:
out.Resource = &proto.Event_Installer{
Installer: r,
Expand Down Expand Up @@ -444,6 +448,9 @@ func EventFromGRPC(in *proto.Event) (*types.Event, error) {
} else if r := in.GetWindowsDesktop(); r != nil {
out.Resource = r
return &out, nil
} else if r := in.GetDynamicWindowsDesktop(); r != nil {
out.Resource = r
return &out, nil
} else if r := in.GetKubernetesServer(); r != nil {
out.Resource = r
return &out, nil
Expand Down
3 changes: 2 additions & 1 deletion api/client/proto/joinservice.pb.go

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

Loading

0 comments on commit 0c9090d

Please sign in to comment.