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

feat: Set CORS headers #4990

Merged
merged 6 commits into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 27 additions & 24 deletions cmd/argo/commands/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,19 @@ import (

func NewServerCommand() *cobra.Command {
var (
authModes []string
configMap string
port int
baseHRef string
secure bool
htst bool
namespaced bool // --namespaced
managedNamespace string // --managed-namespace
enableOpenBrowser bool
eventOperationQueueSize int
eventWorkerCount int
frameOptions string
authModes []string
configMap string
port int
baseHRef string
secure bool
htst bool
namespaced bool // --namespaced
managedNamespace string // --managed-namespace
enableOpenBrowser bool
eventOperationQueueSize int
eventWorkerCount int
frameOptions string
accessControlAllowOrigin string
)

var command = cobra.Command{
Expand Down Expand Up @@ -102,18 +103,19 @@ See %s`, help.ArgoSever),
}

opts := apiserver.ArgoServerOpts{
BaseHRef: baseHRef,
TLSConfig: tlsConfig,
HSTS: htst,
Namespace: namespace,
Clients: clients,
RestConfig: config,
AuthModes: modes,
ManagedNamespace: managedNamespace,
ConfigName: configMap,
EventOperationQueueSize: eventOperationQueueSize,
EventWorkerCount: eventWorkerCount,
XFrameOptions: frameOptions,
BaseHRef: baseHRef,
TLSConfig: tlsConfig,
HSTS: htst,
Namespace: namespace,
Clients: clients,
RestConfig: config,
AuthModes: modes,
ManagedNamespace: managedNamespace,
ConfigName: configMap,
EventOperationQueueSize: eventOperationQueueSize,
EventWorkerCount: eventWorkerCount,
XFrameOptions: frameOptions,
AccessControlAllowOrigin: accessControlAllowOrigin,
}
browserOpenFunc := func(url string) {}
if enableOpenBrowser {
Expand Down Expand Up @@ -148,5 +150,6 @@ See %s`, help.ArgoSever),
command.Flags().IntVar(&eventOperationQueueSize, "event-operation-queue-size", 16, "how many events operations that can be queued at once")
command.Flags().IntVar(&eventWorkerCount, "event-worker-count", 4, "how many event workers to run")
command.Flags().StringVar(&frameOptions, "x-frame-options", "DENY", "Set X-Frame-Options header in HTTP responses.")
command.Flags().StringVar(&accessControlAllowOrigin, "access-control-allow-origin", "", "Set Access-Control-Allow-Origin header in HTTP responses.")
return &command
}
25 changes: 13 additions & 12 deletions docs/cli/argo_server.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,19 @@ See https://argoproj.github.io/argo/argo-server.md
### Options

```
--auth-mode stringArray API server authentication mode. Any 1 or more length permutation of: client,server,sso (default [server])
--basehref string Value for base href in index.html. Used if the server is running behind reverse proxy under subpath different from /. Defaults to the environment variable BASE_HREF. (default "/")
-b, --browser enable automatic launching of the browser [local mode]
--configmap string Name of K8s configmap to retrieve workflow controller configuration (default "workflow-controller-configmap")
--event-operation-queue-size int how many events operations that can be queued at once (default 16)
--event-worker-count int how many event workers to run (default 4)
-h, --help help for server
--hsts Whether or not we should add a HTTP Secure Transport Security header. This only has effect if secure is enabled. (default true)
--managed-namespace string namespace that watches, default to the installation namespace
--namespaced run as namespaced mode
-p, --port int Port to listen on (default 2746)
--x-frame-options string Set X-Frame-Options header in HTTP responses. (default "DENY")
--access-control-allow-origin string Set Access-Control-Allow-Origin header in HTTP responses.
--auth-mode stringArray API server authentication mode. Any 1 or more length permutation of: client,server,sso (default [server])
--basehref string Value for base href in index.html. Used if the server is running behind reverse proxy under subpath different from /. Defaults to the environment variable BASE_HREF. (default "/")
-b, --browser enable automatic launching of the browser [local mode]
--configmap string Name of K8s configmap to retrieve workflow controller configuration (default "workflow-controller-configmap")
--event-operation-queue-size int how many events operations that can be queued at once (default 16)
--event-worker-count int how many event workers to run (default 4)
-h, --help help for server
--hsts Whether or not we should add a HTTP Secure Transport Security header. This only has effect if secure is enabled. (default true)
--managed-namespace string namespace that watches, default to the installation namespace
--namespaced run as namespaced mode
-p, --port int Port to listen on (default 2746)
--x-frame-options string Set X-Frame-Options header in HTTP responses. (default "DENY")
```

### Options inherited from parent commands
Expand Down
67 changes: 35 additions & 32 deletions server/apiserver/argoserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,19 @@ const (
type argoServer struct {
baseHRef string
// https://itnext.io/practical-guide-to-securing-grpc-connections-with-go-and-tls-part-1-f63058e9d6d1
tlsConfig *tls.Config
hsts bool
namespace string
managedNamespace string
clients *types.Clients
gatekeeper auth.Gatekeeper
oAuth2Service sso.Interface
configController config.Controller
stopCh chan struct{}
eventQueueSize int
eventWorkerCount int
xframeOptions string
tlsConfig *tls.Config
hsts bool
namespace string
managedNamespace string
clients *types.Clients
gatekeeper auth.Gatekeeper
oAuth2Service sso.Interface
configController config.Controller
stopCh chan struct{}
eventQueueSize int
eventWorkerCount int
xframeOptions string
accessControlAllowOrigin string
}

type ArgoServerOpts struct {
Expand All @@ -86,12 +87,13 @@ type ArgoServerOpts struct {
RestConfig *rest.Config
AuthModes auth.Modes
// config map name
ConfigName string
ManagedNamespace string
HSTS bool
EventOperationQueueSize int
EventWorkerCount int
XFrameOptions string
ConfigName string
ManagedNamespace string
HSTS bool
EventOperationQueueSize int
EventWorkerCount int
XFrameOptions string
AccessControlAllowOrigin string
}

func NewArgoServer(ctx context.Context, opts ArgoServerOpts) (*argoServer, error) {
Expand All @@ -115,19 +117,20 @@ func NewArgoServer(ctx context.Context, opts ArgoServerOpts) (*argoServer, error
return nil, err
}
return &argoServer{
baseHRef: opts.BaseHRef,
tlsConfig: opts.TLSConfig,
hsts: opts.HSTS,
namespace: opts.Namespace,
managedNamespace: opts.ManagedNamespace,
clients: opts.Clients,
gatekeeper: gatekeeper,
oAuth2Service: ssoIf,
configController: configController,
stopCh: make(chan struct{}),
eventQueueSize: opts.EventOperationQueueSize,
eventWorkerCount: opts.EventWorkerCount,
xframeOptions: opts.XFrameOptions,
baseHRef: opts.BaseHRef,
tlsConfig: opts.TLSConfig,
hsts: opts.HSTS,
namespace: opts.Namespace,
managedNamespace: opts.ManagedNamespace,
clients: opts.Clients,
gatekeeper: gatekeeper,
oAuth2Service: ssoIf,
configController: configController,
stopCh: make(chan struct{}),
eventQueueSize: opts.EventOperationQueueSize,
eventWorkerCount: opts.EventWorkerCount,
xframeOptions: opts.XFrameOptions,
accessControlAllowOrigin: opts.AccessControlAllowOrigin,
}, nil
}

Expand Down Expand Up @@ -307,7 +310,7 @@ func (as *argoServer) newHTTPServer(ctx context.Context, port int, artifactServe
mux.HandleFunc("/oauth2/callback", as.oAuth2Service.HandleCallback)
mux.Handle("/metrics", promhttp.Handler())
// we only enable HTST if we are secure mode, otherwise you would never be able access the UI
mux.HandleFunc("/", static.NewFilesServer(as.baseHRef, as.tlsConfig != nil && as.hsts, as.xframeOptions).ServerFiles)
mux.HandleFunc("/", static.NewFilesServer(as.baseHRef, as.tlsConfig != nil && as.hsts, as.xframeOptions, as.accessControlAllowOrigin).ServerFiles)
return &httpServer
}

Expand Down
23 changes: 18 additions & 5 deletions server/static/static.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import (
)

type FilesServer struct {
baseHRef string
hsts bool
xframeOpts string
baseHRef string
hsts bool
xframeOpts string
corsAllowOrigin string
}

func NewFilesServer(baseHRef string, hsts bool, xframeOpts string) *FilesServer {
return &FilesServer{baseHRef, hsts, xframeOpts}
func NewFilesServer(baseHRef string, hsts bool, xframeOpts string, corsAllowOrigin string) *FilesServer {
return &FilesServer{baseHRef, hsts, xframeOpts, corsAllowOrigin}
}

func (s *FilesServer) ServerFiles(w http.ResponseWriter, r *http.Request) {
Expand All @@ -31,6 +32,18 @@ func (s *FilesServer) ServerFiles(w http.ResponseWriter, r *http.Request) {
if s.xframeOpts != "" {
w.Header().Set("X-Frame-Options", s.xframeOpts)
}

if s.corsAllowOrigin != "" {
w.Header().Set("Access-Control-Allow-Origin", s.corsAllowOrigin)
if r.Method == http.MethodOptions { // Set CORS headers for preflight request
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
w.WriteHeader(http.StatusNoContent)
return
}
}

// `data:` is need for Monaco editors wiggly red lines
w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-inline'; img-src 'self' data:")
if s.hsts {
Expand Down