use service accounts for search

Signed-off-by: jkoberg <jkoberg@owncloud.com>
This commit is contained in:
jkoberg
2023-08-11 14:10:10 +02:00
parent 900afb9bee
commit d8c2957c84
5 changed files with 25 additions and 49 deletions

View File

@@ -29,7 +29,13 @@ type Config struct {
Extractor Extractor `yaml:"extractor"`
ContentExtractionSizeLimit uint64 `yaml:"content_extraction_size_limit" env:"SEARCH_CONTENT_EXTRACTION_SIZE_LIMIT" desc:"Maximum file size in bytes that is allowed for content extraction."`
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;SEARCH_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary for the access to resources from other services."`
ServiceAccount ServiceAccount `yaml:"service_account"`
Context context.Context `yaml:"-"`
}
// ServiceAccount is the configuration for the used service account
type ServiceAccount struct {
ServiceAccountID string `yaml:"service_account_id" env:"OCIS_SERVICE_ACCOUNT_ID;SEARCH_SERVICE_ACCOUNT_ID" desc:"The ID of the service account the service should use. See the 'auth-service' service description for more details."`
ServiceAccountSecret string `yaml:"service_account_secret" env:"OCIS_SERVICE_ACCOUNT_SECRET;SEARCH_SERVICE_ACCOUNT_SECRET" desc:"The service account secret."`
}

View File

@@ -54,7 +54,10 @@ func DefaultConfig() *config.Config {
EnableTLS: false,
},
ContentExtractionSizeLimit: 20 * 1024 * 1024, // Limit content extraction to <20MB files by default
MachineAuthAPIKey: "",
ServiceAccount: config.ServiceAccount{
ServiceAccountID: "service-user-id",
ServiceAccountSecret: "secret-string",
},
}
}
@@ -91,10 +94,6 @@ func EnsureDefaults(cfg *config.Config) {
cfg.TokenManager = &config.TokenManager{}
}
if cfg.MachineAuthAPIKey == "" && cfg.Commons != nil && cfg.Commons.MachineAuthAPIKey != "" {
cfg.MachineAuthAPIKey = cfg.Commons.MachineAuthAPIKey
}
if cfg.Reva == nil && cfg.Commons != nil {
cfg.Reva = structs.CopyOrZeroValue(cfg.Commons.Reva)
}

View File

@@ -4,7 +4,6 @@ import (
"errors"
ociscfg "github.com/owncloud/ocis/v2/ocis-pkg/config"
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
"github.com/owncloud/ocis/v2/services/search/pkg/config"
"github.com/owncloud/ocis/v2/services/search/pkg/config/defaults"
@@ -34,8 +33,5 @@ func ParseConfig(cfg *config.Config) error {
}
func Validate(cfg *config.Config) error {
if cfg.MachineAuthAPIKey == "" {
return shared.MissingMachineAuthApiKeyError(cfg.Service.Name)
}
return nil
}

View File

@@ -8,18 +8,14 @@ import (
"strings"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
searchmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/search/v0"
"github.com/owncloud/ocis/v2/services/search/pkg/engine"
"google.golang.org/grpc/metadata"
)
var scopeRegex = regexp.MustCompile(`scope:\s*([^" "\n\r]*)`)
@@ -71,30 +67,14 @@ func logDocCount(engine engine.Engine, logger log.Logger) {
logger.Debug().Interface("count", c).Msg("new document count")
}
func getAuthContext(owner *user.User, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], secret string, logger log.Logger) (context.Context, error) {
func getAuthContext(serviceAccountID string, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], secret string, logger log.Logger) (context.Context, error) {
gatewayClient, err := gatewaySelector.Next()
if err != nil {
logger.Error().Err(err).Msg("could not get reva gatewayClient")
return nil, err
}
ownerCtx := ctxpkg.ContextSetUser(context.Background(), owner)
authRes, err := gatewayClient.Authenticate(ownerCtx, &gateway.AuthenticateRequest{
Type: "machine",
ClientId: "userid:" + owner.GetId().GetOpaqueId(),
ClientSecret: secret,
})
if err == nil && authRes.GetStatus().GetCode() != rpc.Code_CODE_OK {
err = errtypes.NewErrtypeFromStatus(authRes.Status)
}
if err != nil {
logger.Error().Err(err).Interface("owner", owner).Interface("authRes", authRes).Msg("error using machine auth")
return nil, err
}
return metadata.AppendToOutgoingContext(ownerCtx, ctxpkg.TokenHeader, authRes.Token), nil
return utils.GetServiceUserContext(serviceAccountID, gatewayClient, secret)
}
func statResource(ctx context.Context, ref *provider.Reference, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], logger log.Logger) (*provider.StatResponse, error) {

View File

@@ -57,7 +57,9 @@ type Service struct {
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
engine engine.Engine
extractor content.Extractor
secret string
serviceAccountID string
serviceAccountSecret string
}
var errSkipSpace error
@@ -67,9 +69,11 @@ func NewService(gatewaySelector pool.Selectable[gateway.GatewayAPIClient], eng e
var s = &Service{
gatewaySelector: gatewaySelector,
engine: eng,
secret: cfg.MachineAuthAPIKey,
logger: logger,
extractor: extractor,
serviceAccountID: cfg.ServiceAccount.ServiceAccountID,
serviceAccountSecret: cfg.ServiceAccount.ServiceAccountSecret,
}
return s
@@ -291,21 +295,12 @@ func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest,
return nil, err
}
var ownerCtx context.Context
if space.Owner.Id.Type == user.UserType_USER_TYPE_SPACE_OWNER {
// We can't impersonate SPACE_OWNER users and have to fall back to using the user auth instead,
// which will not resolve the absolute path of the share in the space but only the part the user
// is allowed to see.
// In the future this problem can be solved using service accounts.
ownerCtx = ctx
} else {
ownerCtx, err = getAuthContext(&user.User{Id: space.Owner.Id}, s.gatewaySelector, s.secret, s.logger)
if err != nil {
return nil, err
}
serviceCtx, err := getAuthContext(s.serviceAccountID, s.gatewaySelector, s.serviceAccountSecret, s.logger)
if err != nil {
return nil, err
}
gpRes, err := gatewayClient.GetPath(ownerCtx, &provider.GetPathRequest{
gpRes, err := gatewayClient.GetPath(serviceCtx, &provider.GetPathRequest{
ResourceId: space.Root,
})
if err != nil {
@@ -380,7 +375,7 @@ func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest,
// IndexSpace (re)indexes all resources of a given space.
func (s *Service) IndexSpace(spaceID *provider.StorageSpaceId, uID *user.UserId) error {
ownerCtx, err := getAuthContext(&user.User{Id: uID}, s.gatewaySelector, s.secret, s.logger)
ownerCtx, err := getAuthContext(s.serviceAccountID, s.gatewaySelector, s.serviceAccountSecret, s.logger)
if err != nil {
return err
}
@@ -510,7 +505,7 @@ func (s *Service) MoveItem(ref *provider.Reference, uID *user.UserId) {
}
func (s *Service) resInfo(uID *user.UserId, ref *provider.Reference) (context.Context, *provider.StatResponse, string) {
ownerCtx, err := getAuthContext(&user.User{Id: uID}, s.gatewaySelector, s.secret, s.logger)
ownerCtx, err := getAuthContext(s.serviceAccountID, s.gatewaySelector, s.serviceAccountSecret, s.logger)
if err != nil {
return nil, nil, ""
}