- Notifications
You must be signed in to change notification settings - Fork1.1k
feat: add --key flag to provisionerd start#14002
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
f4f1b1b47aa9c4aa314a37b83b7e727abcde54e66210b09edFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -24,6 +24,7 @@ import ( | ||
| "github.com/coder/coder/v2/cli/cliui" | ||
| "github.com/coder/coder/v2/cli/cliutil" | ||
| "github.com/coder/coder/v2/coderd/database" | ||
| "github.com/coder/coder/v2/coderd/provisionerkey" | ||
| "github.com/coder/coder/v2/codersdk" | ||
| "github.com/coder/coder/v2/codersdk/drpc" | ||
| "github.com/coder/coder/v2/provisioner/terraform" | ||
| @@ -46,6 +47,7 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { | ||
| pollInterval time.Duration | ||
| pollJitter time.Duration | ||
| preSharedKey string | ||
| provisionerKey string | ||
| verbose bool | ||
| prometheusEnable bool | ||
| @@ -83,8 +85,8 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { | ||
| return xerrors.Errorf("current organization: %w", err) | ||
| } | ||
| if preSharedKey == ""&& provisionerKey == ""{ | ||
| return xerrors.New("must provide a pre-shared keyor provisioner keywhen not authenticated as a user") | ||
| } | ||
| org = codersdk.Organization{MinimalOrganization: codersdk.MinimalOrganization{ID: uuid.Nil}} | ||
| @@ -113,6 +115,19 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { | ||
| return err | ||
| } | ||
| if provisionerKey != "" { | ||
| if preSharedKey != "" { | ||
| return xerrors.New("cannot provide both provisioner key --key and pre-shared key --psk") | ||
| } | ||
| if len(rawTags) > 0 { | ||
| return xerrors.New("cannot provide tags when using provisioner key") | ||
| } | ||
| _, _, err := provisionerkey.Parse(provisionerKey) | ||
| if err != nil { | ||
| return xerrors.Errorf("parse provisioner key: %w", err) | ||
| } | ||
| } | ||
| logOpts := []clilog.Option{ | ||
| clilog.WithFilter(logFilter...), | ||
| clilog.WithHuman(logHuman), | ||
| @@ -136,12 +151,17 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { | ||
| logger.Info(ctx, "note: untagged provisioners can only pick up jobs from untagged templates") | ||
| } | ||
| // When authorizing with a PSK / provisioner key, we automatically scope the provisionerd | ||
| // to organization. Scoping to user with PSK/ provisioner keyauth is not a valid configuration. | ||
| if preSharedKey != "" { | ||
| logger.Info(ctx, "psk automatically sets tag "+provisionersdk.TagScope+"="+provisionersdk.ScopeOrganization) | ||
| tags[provisionersdk.TagScope] = provisionersdk.ScopeOrganization | ||
| } | ||
| if provisionerKey != "" { | ||
| logger.Info(ctx, "provisioner key auth automatically sets tag "+provisionersdk.TagScope+" empty") | ||
| // no scope tag will default to org scope | ||
| delete(tags, provisionersdk.TagScope) | ||
| } | ||
Comment on lines +160 to +164 Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Is this because it's all done on coderd? And we should be passing no tags into the provisioner daemon? ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. Correct, the API will actually fail if you pass any tags + a provisioner key. I felt this was a good opportunity to break that behavior altogether. | ||
| err = os.MkdirAll(cacheDir, 0o700) | ||
| if err != nil { | ||
| @@ -210,9 +230,10 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { | ||
| Provisioners: []codersdk.ProvisionerType{ | ||
| codersdk.ProvisionerTypeTerraform, | ||
| }, | ||
| Tags: tags, | ||
| PreSharedKey: preSharedKey, | ||
| Organization: org.ID, | ||
| ProvisionerKey: provisionerKey, | ||
| }) | ||
| }, &provisionerd.Options{ | ||
| Logger: logger, | ||
| @@ -296,6 +317,13 @@ func (r *RootCmd) provisionerDaemonStart() *serpent.Command { | ||
| Description: "Pre-shared key to authenticate with Coder server.", | ||
| Value: serpent.StringOf(&preSharedKey), | ||
| }, | ||
| { | ||
| Flag: "key", | ||
| Env: "CODER_PROVISIONER_DAEMON_KEY", | ||
| Description: "Provisioner key to authenticate with Coder server.", | ||
| Value: serpent.StringOf(&provisionerKey), | ||
| Hidden: true, | ||
| }, | ||
| { | ||
| Flag: "name", | ||
| Env: "CODER_PROVISIONER_DAEMON_NAME", | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -13,6 +13,7 @@ import ( | ||
| "github.com/hashicorp/yamux" | ||
| "github.com/moby/moby/pkg/namesgenerator" | ||
| "go.opentelemetry.io/otel/trace" | ||
| "golang.org/x/exp/maps" | ||
| "golang.org/x/xerrors" | ||
| "nhooyr.io/websocket" | ||
| "storj.io/drpc/drpcmux" | ||
| @@ -97,39 +98,43 @@ func (p *provisionerDaemonAuth) authorize(r *http.Request, orgID uuid.UUID, tags | ||
| return nil, xerrors.New("Both API key and provisioner key authentication provided. Only one is allowed.") | ||
| } | ||
| // Provisioner Key Auth | ||
| if pkOK { | ||
| if pk.OrganizationID != orgID { | ||
| return nil, xerrors.New("provisioner key unauthorized") | ||
| } | ||
| if tags != nil && !maps.Equal(tags, map[string]string{}) { | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. TIL | ||
| return nil, xerrors.New("tags are not allowed when using a provisioner key") | ||
| } | ||
| // If using provisioner key / PSK auth, the daemon is, by definition, scoped to the organization. | ||
| // Use the provisioner key tags here. | ||
| tags = provisionersdk.MutateTags(uuid.Nil, pk.Tags) | ||
| return tags, nil | ||
| } | ||
| // User Auth | ||
| tags = provisionersdk.MutateTags(apiKey.UserID, tags) | ||
| if tags[provisionersdk.TagScope] == provisionersdk.ScopeUser { | ||
| // Any authenticated user can create provisioner daemons scoped | ||
| // for jobs that they own, | ||
| return tags, nil | ||
| } | ||
| ua := httpmw.UserAuthorization(r) | ||
| err := p.authorizer.Authorize(ctx, ua, policy.ActionCreate, rbac.ResourceProvisionerDaemon.InOrg(orgID)) | ||
| if err != nil { | ||
| if !provAuth { | ||
| return nil, xerrors.New("user unauthorized") | ||
| } | ||
| // Allow fallback to PSK auth if the user is not allowed to create provisioner daemons. | ||
| // This is to preserve backwards compatibility with existing user provisioner daemons. | ||
| // If using PSK auth, the daemon is, by definition, scoped to the organization. | ||
| tags = provisionersdk.MutateTags(uuid.Nil, tags) | ||
| return tags, nil | ||
| } | ||
| // User is allowed to create provisioner daemons | ||
| return tags, nil | ||
| } | ||