Skip to content

Commit

Permalink
initial changes
Browse files Browse the repository at this point in the history
  • Loading branch information
pawanpinjarkar committed Mar 19, 2024
1 parent 3864109 commit afb8392
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 5 deletions.
125 changes: 124 additions & 1 deletion cmd/agentbasedinstaller/client/main.go
Expand Up @@ -23,25 +23,51 @@ package main

import (
"context"
"flag"
"fmt"
"net/url"
"os"
"os/signal"
"path"
"strings"
"syscall"
"time"

"github.com/NYTimes/gziphandler"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/openshift/assisted-image-service/pkg/servers"
"github.com/openshift/assisted-service/cmd/agentbasedinstaller"
"github.com/openshift/assisted-service/internal/common"
"github.com/openshift/assisted-service/internal/spec"
"github.com/openshift/assisted-service/pkg/app"
"github.com/openshift/assisted-service/pkg/auth"
dbPkg "github.com/openshift/assisted-service/pkg/db"
"github.com/openshift/assisted-service/pkg/requestid"
"github.com/openshift/assisted-service/restapi"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"k8s.io/apimachinery/pkg/util/wait"

"github.com/kelseyhightower/envconfig"
"github.com/openshift/assisted-service/client"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
)

const failureOutputPath = "/var/run/agent-installer/host-config-failures"

var Options struct {
ServiceBaseUrl string `envconfig:"SERVICE_BASE_URL" default:""`
Auth auth.Config
DBConfig dbPkg.Config
ServiceBaseUrl string `envconfig:"SERVICE_BASE_URL" default:""`
MaxIdleConns int `envconfig:"DB_MAX_IDLE_CONNECTIONS" default:"50"`
MaxOpenConns int `envconfig:"DB_MAX_OPEN_CONNECTIONS" default:"90"`
ConnMaxLifetime time.Duration `envconfig:"DB_CONNECTIONS_MAX_LIFETIME" default:"30m"`
HTTPSKeyFile string `envconfig:"HTTPS_KEY_FILE" default:""`
HTTPSCertFile string `envconfig:"HTTPS_CERT_FILE" default:""`
HTTPListenPort string `envconfig:"HTTP_LISTEN_PORT" default:""`
}

var RegisterOptions struct {
Expand Down Expand Up @@ -73,6 +99,7 @@ func main() {
if err != nil {
log.Fatal(err.Error())
}


clientConfig := client.Config{}
u, parseErr := url.Parse(Options.ServiceBaseUrl)
Expand All @@ -95,6 +122,65 @@ func main() {
if len(os.Args) < 2 {
log.Fatal("No subcommand specified")
}

// Connect to db
db := setupDB(log)
defer common.CloseDB(db)

authHandler, err := auth.NewAuthenticator(&Options.Auth, nil, log.WithField("pkg", "auth"), db)
failOnError := func(err error, msg string, args ...interface{}) {
if err != nil {
log.WithError(err).Fatalf(msg, args...)
}
}
failOnError(err, "failed to create authenticator")

h, err := restapi.Handler(restapi.Config{
AuthAgentAuth: authHandler.AuthAgentAuth,
AuthUserAuth: authHandler.AuthUserAuth,
AuthURLAuth: authHandler.AuthURLAuth,
AuthImageAuth: authHandler.AuthImageAuth,
AuthImageURLAuth: authHandler.AuthImageAuth,
// APIKeyAuthenticator: authHandler.CreateAuthenticator(),
// Authorizer: authzHandler.CreateAuthorizer(),
// InstallerAPI: bm,
// EventsAPI: events,
Logger: log.Printf,
// VersionsAPI: versionsAPIHandler,
// ManagedDomainsAPI: domainHandler,
// InnerMiddleware: innerHandler(),
// ManifestsAPI: manifestsApi,
// OperatorsAPI: operatorsHandler,
// JSONConsumer: jsonConsumer,
})
failOnError(err, "Failed to init rest handler")

h = gziphandler.GzipHandler(h)
h = app.WithMetricsResponderMiddleware(h)
// h = app.WithHealthMiddleware(h, []*thread.Thread{hostStateMonitor, clusterStateMonitor},
// log.WithField("pkg", "healthcheck"), Options.LivenessValidationTimeout)
h = requestid.Middleware(h)
h = spec.WithSpecMiddleware(h)

port := flag.String("port", "8090", "define port that the service will listen to")
flag.Parse()

serverInfo := servers.New(Options.HTTPListenPort, swag.StringValue(port), Options.HTTPSKeyFile, Options.HTTPSCertFile)

// Interrupt servers on SIGINT/SIGTERM
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

if serverInfo.HTTP != nil {
serverInfo.HTTP.Handler = h
}
if serverInfo.HTTPS != nil {
serverInfo.HTTPS.Handler = h
}
serverInfo.ListenAndServe()
<-stop
serverInfo.Shutdown()

switch os.Args[1] {
case "register":
// registers both cluster and infraenv
Expand Down Expand Up @@ -145,6 +231,43 @@ func register(ctx context.Context, log *log.Logger, bmInventory *client.Assisted
return modelsInfraEnv.ID.String()
}

func setupDB(log logrus.FieldLogger) *gorm.DB {
dbConnectionStr := fmt.Sprintf("host=%s port=%s user=%s database=%s password=%s sslmode=disable",
Options.DBConfig.Host, Options.DBConfig.Port, Options.DBConfig.User, Options.DBConfig.Name, Options.DBConfig.Pass)
var db *gorm.DB
var err error
// Tries to open a db connection every 2 seconds
retryInterval := 2 * time.Second
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
log.Info("Connecting to DB")
wait.UntilWithContext(ctx, func(ctx context.Context) {
db, err = gorm.Open(postgres.Open(dbConnectionStr), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true,
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
log.WithError(err).Info("Failed to connect to DB, retrying")
return
}
sqlDB, err := db.DB()
if err != nil {
log.WithError(err).Info("Failed to get sqlDB, retrying")
common.CloseDB(db)
return
}
sqlDB.SetMaxIdleConns(Options.MaxIdleConns)
sqlDB.SetMaxOpenConns(Options.MaxOpenConns)
sqlDB.SetConnMaxLifetime(Options.ConnMaxLifetime)
cancel()
}, retryInterval)
if ctx.Err().Error() == context.DeadlineExceeded.Error() {
log.WithError(ctx.Err()).Fatal("Timed out connecting to DB")
}
log.Info("Connected to DB")
return db
}

func registerCluster(ctx context.Context, log *log.Logger, bmInventory *client.AssistedInstall) string {
err := envconfig.Process("", &RegisterOptions)
if err != nil {
Expand Down
112 changes: 112 additions & 0 deletions pkg/auth/agent_local_authenticator.go
@@ -0,0 +1,112 @@
package auth

import (
"crypto"
"net/http"
"time"

"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/security"
"github.com/golang-jwt/jwt/v4"
"github.com/openshift/assisted-service/internal/common"
"github.com/openshift/assisted-service/internal/gencrypto"

"github.com/openshift/assisted-service/pkg/ocm"
"github.com/patrickmn/go-cache"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"gorm.io/gorm"
)

type AgentLocalAuthenticator struct {
cache *cache.Cache
db *gorm.DB
log logrus.FieldLogger
publicKey crypto.PublicKey
}

func NewAgentLocalAuthenticator(cfg *Config, log logrus.FieldLogger, db *gorm.DB) (*AgentLocalAuthenticator, error) {
if cfg.ECPublicKeyPEM == "" {
return nil, errors.Errorf("agent installer local authentication requires an ecdsa Public Key")
}

key, err := jwt.ParseECPublicKeyFromPEM([]byte(cfg.ECPublicKeyPEM))
if err != nil {
return nil, err
}

a := &AgentLocalAuthenticator{
cache: cache.New(10*time.Minute, 30*time.Minute),
db: db,
log: log,
publicKey: key,
}

return a, nil
}

var _ Authenticator = &AgentLocalAuthenticator{}

func (a *AgentLocalAuthenticator) AuthType() AuthType {
return TypeAgentLocal
}

func (a *AgentLocalAuthenticator) EnableOrgTenancy() bool {
return false
}

func (a *AgentLocalAuthenticator) EnableOrgBasedFeatureGates() bool {
return false
}

func (a *AgentLocalAuthenticator) AuthAgentAuth(token string) (interface{}, error) {
t, err := validateToken(token, a.publicKey)
if err != nil {
a.log.WithError(err).Error("failed to validate token")
return nil, common.NewInfraError(http.StatusUnauthorized, err)
}
claims, ok := t.Claims.(jwt.MapClaims)
if !ok {
err := errors.Errorf("failed to parse JWT token claims")
a.log.Error(err)
return nil, common.NewInfraError(http.StatusUnauthorized, err)
}

infraEnvID, infraEnvOk := claims[string(gencrypto.InfraEnvKey)].(string)
if !infraEnvOk {
err := errors.Errorf("claims are incorrectly formatted")
a.log.Error(err)
return nil, common.NewInfraError(http.StatusUnauthorized, err)
}

if infraEnvOk {
_, exists := a.cache.Get(infraEnvID)
if !exists {
if infraEnvExists(a.db, infraEnvID) {
a.cache.Set(infraEnvID, "", cache.DefaultExpiration)
} else {
err := errors.Errorf("infraEnv %s does not exist", infraEnvID)
return nil, common.NewInfraError(http.StatusUnauthorized, err)
}
}
a.log.Debugf("Authenticating infraEnv %s JWT", infraEnvID)
}

return ocm.AdminPayload(), nil
}

func (a *AgentLocalAuthenticator) AuthUserAuth(token string) (interface{}, error) {
return a.AuthAgentAuth(token)
}

func (a *AgentLocalAuthenticator) AuthURLAuth(token string) (interface{}, error) {
return a.AuthAgentAuth(token)
}

func (a *AgentLocalAuthenticator) AuthImageAuth(_ string) (interface{}, error) {
return nil, common.NewInfraError(http.StatusUnauthorized, errors.Errorf("Image Authentication not allowed for agent local auth"))
}

func (a *AgentLocalAuthenticator) CreateAuthenticator() func(_, _ string, _ security.TokenAuthentication) runtime.Authenticator {
return security.APIKeyAuth
}
11 changes: 7 additions & 4 deletions pkg/auth/authenticator.go
Expand Up @@ -13,10 +13,11 @@ import (
type AuthType string

const (
TypeEmpty AuthType = ""
TypeNone AuthType = "none"
TypeRHSSO AuthType = "rhsso"
TypeLocal AuthType = "local"
TypeEmpty AuthType = ""
TypeNone AuthType = "none"
TypeRHSSO AuthType = "rhsso"
TypeLocal AuthType = "local"
TypeAgentLocal AuthType = "agent-installer-local"
)

type Authenticator interface {
Expand Down Expand Up @@ -50,6 +51,8 @@ func NewAuthenticator(cfg *Config, ocmClient *ocm.Client, log logrus.FieldLogger
a = NewNoneAuthenticator(log)
case TypeLocal:
a, err = NewLocalAuthenticator(cfg, log, db)
case TypeAgentLocal:
a, err = NewAgentLocalAuthenticator(cfg, log, db)
default:
err = fmt.Errorf("invalid authenticator type %v", cfg.AuthType)
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/auth/authenticator_test.go
Expand Up @@ -48,5 +48,19 @@ var _ = Describe("NewAuthenticator", func() {
Expect(err).ToNot(HaveOccurred())
_, ok = a.(*LocalAuthenticator)
Expect(ok).To(BeTrue())

// AgentLocalAuthenticator
pubKey, _, err = gencrypto.ECDSAKeyPairPEM()
Expect(err).ToNot(HaveOccurred())
config = &Config{
AuthType: TypeAgentLocal,
ECPublicKeyPEM: pubKey,
}

a, err = NewAuthenticator(config, nil, logrus.New(), nil)
Expect(err).ToNot(HaveOccurred())
_, ok = a.(*LocalAuthenticator)
Expect(ok).To(BeTrue())

})
})

0 comments on commit afb8392

Please sign in to comment.