Skip to content

Commit

Permalink
Merge pull request #163 from gabriel-samfira/add-jit-config
Browse files Browse the repository at this point in the history
Add jit config
  • Loading branch information
gabriel-samfira authored Sep 24, 2023
2 parents 6089f17 + 019948a commit a48ec0c
Show file tree
Hide file tree
Showing 18 changed files with 783 additions and 89 deletions.
72 changes: 72 additions & 0 deletions apiserver/controllers/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ package controllers

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

"github.com/cloudbase/garm/apiserver/params"
"github.com/gorilla/mux"
)

func (a *APIController) InstanceGithubRegistrationTokenHandler(w http.ResponseWriter, r *http.Request) {
Expand All @@ -36,6 +40,74 @@ func (a *APIController) InstanceGithubRegistrationTokenHandler(w http.ResponseWr
}
}

func (a *APIController) JITCredentialsFileHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
fileName, ok := vars["fileName"]
if !ok {
w.WriteHeader(http.StatusNotFound)
if err := json.NewEncoder(w).Encode(params.APIErrorResponse{
Error: "Not Found",
Details: "Not Found",
}); err != nil {
log.Printf("failed to encode response: %q", err)
}
return
}

dotFileName := fmt.Sprintf(".%s", fileName)

data, err := a.r.GetJITConfigFile(ctx, dotFileName)
if err != nil {
log.Printf("getting JIT config file: %s", err)
handleError(w, err)
return
}

// Note the leading dot in the filename
name := fmt.Sprintf("attachment; filename=%s", dotFileName)
w.Header().Set("Content-Disposition", name)
w.Header().Set("Content-Type", "octet-stream")
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(data)))
w.WriteHeader(http.StatusOK)
if _, err := w.Write(data); err != nil {
log.Printf("failed to encode response: %q", err)
}
}

func (a *APIController) SystemdServiceNameHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

serviceName, err := a.r.GetRunnerServiceName(ctx)
if err != nil {
handleError(w, err)
return
}

w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte(serviceName)); err != nil {
log.Printf("failed to encode response: %q", err)
}
}

func (a *APIController) SystemdUnitFileHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
runAsUser := r.URL.Query().Get("runAsUser")

data, err := a.r.GenerateSystemdUnitFile(ctx, runAsUser)
if err != nil {
handleError(w, err)
return
}

w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
if _, err := w.Write(data); err != nil {
log.Printf("failed to encode response: %q", err)
}
}

func (a *APIController) RootCertificateBundleHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

Expand Down
8 changes: 8 additions & 0 deletions apiserver/routers/routers.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ func NewAPIRouter(han *controllers.APIController, logWriter io.Writer, authMiddl
// Registration token
metadataRouter.Handle("/runner-registration-token/", http.HandlerFunc(han.InstanceGithubRegistrationTokenHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/runner-registration-token", http.HandlerFunc(han.InstanceGithubRegistrationTokenHandler)).Methods("GET", "OPTIONS")
// JIT credential files
metadataRouter.Handle("/credentials/{fileName}/", http.HandlerFunc(han.JITCredentialsFileHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/credentials/{fileName}", http.HandlerFunc(han.JITCredentialsFileHandler)).Methods("GET", "OPTIONS")
// Systemd files
metadataRouter.Handle("/system/service-name/", http.HandlerFunc(han.SystemdServiceNameHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/system/service-name", http.HandlerFunc(han.SystemdServiceNameHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/systemd/unit-file/", http.HandlerFunc(han.SystemdUnitFileHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/systemd/unit-file", http.HandlerFunc(han.SystemdUnitFileHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/system/cert-bundle/", http.HandlerFunc(han.RootCertificateBundleHandler)).Methods("GET", "OPTIONS")
metadataRouter.Handle("/system/cert-bundle", http.HandlerFunc(han.RootCertificateBundleHandler)).Methods("GET", "OPTIONS")

Expand Down
14 changes: 14 additions & 0 deletions auth/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const (
instanceEntityKey contextFlags = "entity"
instanceRunnerStatus contextFlags = "status"
instanceTokenFetched contextFlags = "tokenFetched"
instanceHasJITConfig contextFlags = "hasJITConfig"
instanceParams contextFlags = "instanceParams"
)

Expand Down Expand Up @@ -66,6 +67,18 @@ func InstanceTokenFetched(ctx context.Context) bool {
return elem.(bool)
}

func SetInstanceHasJITConfig(ctx context.Context, cfg map[string]string) context.Context {
return context.WithValue(ctx, instanceHasJITConfig, len(cfg) > 0)
}

func InstanceHasJITConfig(ctx context.Context) bool {
elem := ctx.Value(instanceHasJITConfig)
if elem == nil {
return false
}
return elem.(bool)
}

func SetInstanceParams(ctx context.Context, instance params.Instance) context.Context {
return context.WithValue(ctx, instanceParams, instance)
}
Expand Down Expand Up @@ -149,6 +162,7 @@ func PopulateInstanceContext(ctx context.Context, instance params.Instance) cont
ctx = SetInstancePoolID(ctx, instance.PoolID)
ctx = SetInstanceRunnerStatus(ctx, instance.RunnerStatus)
ctx = SetInstanceTokenFetched(ctx, instance.TokenFetched)
ctx = SetInstanceHasJITConfig(ctx, instance.JitConfiguration)
ctx = SetInstanceParams(ctx, instance)
return ctx
}
Expand Down
38 changes: 38 additions & 0 deletions database/sql/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"encoding/json"

runnerErrors "github.com/cloudbase/garm-provider-common/errors"
"github.com/cloudbase/garm-provider-common/util"
"github.com/cloudbase/garm/params"

"github.com/google/uuid"
Expand All @@ -28,6 +29,25 @@ import (
"gorm.io/gorm/clause"
)

func (s *sqlDatabase) marshalAndSeal(data interface{}) ([]byte, error) {
enc, err := json.Marshal(data)
if err != nil {
return nil, errors.Wrap(err, "marshalling data")
}
return util.Seal(enc, []byte(s.cfg.Passphrase))
}

func (s *sqlDatabase) unsealAndUnmarshal(data []byte, target interface{}) error {
decrypted, err := util.Unseal(data, []byte(s.cfg.Passphrase))
if err != nil {
return errors.Wrap(err, "decrypting data")
}
if err := json.Unmarshal(decrypted, target); err != nil {
return errors.Wrap(err, "unmarshalling data")
}
return nil
}

func (s *sqlDatabase) CreateInstance(ctx context.Context, poolID string, param params.CreateInstanceParams) (params.Instance, error) {
pool, err := s.getPoolByID(ctx, poolID)
if err != nil {
Expand All @@ -42,6 +62,14 @@ func (s *sqlDatabase) CreateInstance(ctx context.Context, poolID string, param p
}
}

var secret []byte
if len(param.JitConfiguration) > 0 {
secret, err = s.marshalAndSeal(param.JitConfiguration)
if err != nil {
return params.Instance{}, errors.Wrap(err, "marshalling jit config")
}
}

newInstance := Instance{
Pool: pool,
Name: param.Name,
Expand All @@ -52,7 +80,9 @@ func (s *sqlDatabase) CreateInstance(ctx context.Context, poolID string, param p
CallbackURL: param.CallbackURL,
MetadataURL: param.MetadataURL,
GitHubRunnerGroup: param.GitHubRunnerGroup,
JitConfiguration: secret,
AditionalLabels: labels,
AgentID: param.AgentID,
}
q := s.conn.Create(&newInstance)
if q.Error != nil {
Expand Down Expand Up @@ -235,6 +265,14 @@ func (s *sqlDatabase) UpdateInstance(ctx context.Context, instanceID string, par
instance.TokenFetched = *param.TokenFetched
}

if param.JitConfiguration != nil {
secret, err := s.marshalAndSeal(param.JitConfiguration)
if err != nil {
return params.Instance{}, errors.Wrap(err, "marshalling jit config")
}
instance.JitConfiguration = secret
}

instance.ProviderFault = param.ProviderFault

q := s.conn.Save(&instance)
Expand Down
1 change: 1 addition & 0 deletions database/sql/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ type Instance struct {
ProviderFault []byte `gorm:"type:longblob"`
CreateAttempt int
TokenFetched bool
JitConfiguration []byte `gorm:"type:longblob"`
GitHubRunnerGroup string
AditionalLabels datatypes.JSON

Expand Down
7 changes: 7 additions & 0 deletions database/sql/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ func (s *sqlDatabase) sqlToParamsInstance(instance Instance) (params.Instance, e
}
}

var jitConfig map[string]string
if len(instance.JitConfiguration) > 0 {
if err := s.unsealAndUnmarshal(instance.JitConfiguration, &jitConfig); err != nil {
return params.Instance{}, errors.Wrap(err, "unmarshalling jit configuration")
}
}
ret := params.Instance{
ID: instance.ID.String(),
ProviderID: id,
Expand All @@ -59,6 +65,7 @@ func (s *sqlDatabase) sqlToParamsInstance(instance Instance) (params.Instance, e
CreateAttempt: instance.CreateAttempt,
UpdatedAt: instance.UpdatedAt,
TokenFetched: instance.TokenFetched,
JitConfiguration: jitConfig,
GitHubRunnerGroup: instance.GitHubRunnerGroup,
AditionalLabels: labels,
}
Expand Down
11 changes: 6 additions & 5 deletions params/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,12 @@ type Instance struct {
GitHubRunnerGroup string `json:"github-runner-group"`

// Do not serialize sensitive info.
CallbackURL string `json:"-"`
MetadataURL string `json:"-"`
CreateAttempt int `json:"-"`
TokenFetched bool `json:"-"`
AditionalLabels []string `json:"-"`
CallbackURL string `json:"-"`
MetadataURL string `json:"-"`
CreateAttempt int `json:"-"`
TokenFetched bool `json:"-"`
AditionalLabels []string `json:"-"`
JitConfiguration map[string]string `json:"-"`
}

func (i Instance) GetName() string {
Expand Down
17 changes: 10 additions & 7 deletions params/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,10 @@ type CreateInstanceParams struct {
// GithubRunnerGroup is the github runner group to which the runner belongs.
// The runner group must be created by someone with access to the enterprise.
GitHubRunnerGroup string
CreateAttempt int `json:"-"`
CreateAttempt int `json:"-"`
AgentID int64 `json:"-"`
AditionalLabels []string
JitConfiguration map[string]string
}

type CreatePoolParams struct {
Expand Down Expand Up @@ -198,12 +200,13 @@ type UpdateInstanceParams struct {
// for this instance.
Addresses []commonParams.Address `json:"addresses,omitempty"`
// Status is the status of the instance inside the provider (eg: running, stopped, etc)
Status commonParams.InstanceStatus `json:"status,omitempty"`
RunnerStatus RunnerStatus `json:"runner_status,omitempty"`
ProviderFault []byte `json:"provider_fault,omitempty"`
AgentID int64 `json:"-"`
CreateAttempt int `json:"-"`
TokenFetched *bool `json:"-"`
Status commonParams.InstanceStatus `json:"status,omitempty"`
RunnerStatus RunnerStatus `json:"runner_status,omitempty"`
ProviderFault []byte `json:"provider_fault,omitempty"`
AgentID int64 `json:"-"`
CreateAttempt int `json:"-"`
TokenFetched *bool `json:"-"`
JitConfiguration map[string]string `json:"-"`
}

type UpdateUserParams struct {
Expand Down
Loading

0 comments on commit a48ec0c

Please sign in to comment.