mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-24 22:49:06 -06:00
use service accounts for storage-user commands
Signed-off-by: jkoberg <jkoberg@owncloud.com>
This commit is contained in:
@@ -38,6 +38,7 @@ type Config struct {
|
||||
ReadOnly bool `yaml:"readonly" env:"STORAGE_USERS_READ_ONLY" desc:"Set this storage to be read-only."`
|
||||
UploadExpiration int64 `yaml:"upload_expiration" env:"STORAGE_USERS_UPLOAD_EXPIRATION" desc:"Duration in seconds after which uploads will expire. Note that when setting this to a low number, uploads could be cancelled before they are finished and return a 403 to the user."`
|
||||
Tasks Tasks `yaml:"tasks"`
|
||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||
|
||||
Supervised bool `yaml:"-"`
|
||||
Context context.Context `yaml:"-"`
|
||||
@@ -278,3 +279,9 @@ type PurgeTrashBin struct {
|
||||
PersonalDeleteBefore time.Duration `yaml:"personal_delete_before" env:"STORAGE_USERS_PURGE_TRASH_BIN_PERSONAL_DELETE_BEFORE" desc:"Specifies the period of time in which items that have been in the personal trash-bin for longer than this value should be deleted. A value of 0 means no automatic deletion. The value is human-readable, valid values are '24h', '60m', '60s' etc."`
|
||||
ProjectDeleteBefore time.Duration `yaml:"project_delete_before" env:"STORAGE_USERS_PURGE_TRASH_BIN_PROJECT_DELETE_BEFORE" desc:"Specifies the period of time in which items that have been in the project trash-bin for longer than this value should be deleted. A value of 0 means no automatic deletion. The value is human-readable, valid values are '24h', '60m', '60s' etc."`
|
||||
}
|
||||
|
||||
// ServiceAccount is the configuration for the used service account
|
||||
type ServiceAccount struct {
|
||||
ServiceAccountID string `yaml:"service_account_id" env:"OCIS_SERVICE_ACCOUNT_ID;STORAGE_USERS_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;STORAGE_USERS_SERVICE_ACCOUNT_SECRET" desc:"The service account secret."`
|
||||
}
|
||||
|
||||
@@ -108,6 +108,10 @@ func DefaultConfig() *config.Config {
|
||||
PersonalDeleteBefore: 30 * 24 * time.Hour,
|
||||
},
|
||||
},
|
||||
ServiceAccount: config.ServiceAccount{
|
||||
ServiceAccountID: "service-user-id",
|
||||
ServiceAccountSecret: "secret-string",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"time"
|
||||
|
||||
apiGateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
apiUser "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/events"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
@@ -53,11 +52,6 @@ func (s Service) Run() error {
|
||||
executionTime = time.Now()
|
||||
}
|
||||
|
||||
executantID := ev.ExecutantID
|
||||
if executantID == nil {
|
||||
executantID = &apiUser.UserId{OpaqueId: s.config.Tasks.PurgeTrashBin.UserID}
|
||||
}
|
||||
|
||||
tasks := map[task.SpaceType]time.Time{
|
||||
task.Project: executionTime.Add(-s.config.Tasks.PurgeTrashBin.ProjectDeleteBefore),
|
||||
task.Personal: executionTime.Add(-s.config.Tasks.PurgeTrashBin.PersonalDeleteBefore),
|
||||
@@ -70,7 +64,7 @@ func (s Service) Run() error {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = task.PurgeTrashBin(executantID, deleteBefore, spaceType, s.gatewaySelector, s.config.Commons.MachineAuthAPIKey); err != nil {
|
||||
if err = task.PurgeTrashBin(s.config.ServiceAccount.ServiceAccountID, deleteBefore, spaceType, s.gatewaySelector, s.config.ServiceAccount.ServiceAccountSecret); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
apiGateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
apiUser "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
apiRpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
apiProvider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
@@ -17,18 +15,18 @@ import (
|
||||
// the provided executantID must have space access.
|
||||
// removeBefore specifies how long an item must be in the trash-bin to be deleted,
|
||||
// items that stay there for a shorter time are ignored and kept in place.
|
||||
func PurgeTrashBin(executantID *apiUser.UserId, deleteBefore time.Time, spaceType SpaceType, gatewaySelector pool.Selectable[apiGateway.GatewayAPIClient], machineAuthAPIKey string) error {
|
||||
func PurgeTrashBin(serviceAccountID string, deleteBefore time.Time, spaceType SpaceType, gatewaySelector pool.Selectable[apiGateway.GatewayAPIClient], serviceAccountSecret string) error {
|
||||
gatewayClient, err := gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
executantCtx, _, err := utils.Impersonate(executantID, gatewayClient, machineAuthAPIKey)
|
||||
ctx, err := utils.GetServiceUserContext(serviceAccountID, gatewayClient, serviceAccountSecret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
listStorageSpacesResponse, err := gatewayClient.ListStorageSpaces(executantCtx, &apiProvider.ListStorageSpacesRequest{
|
||||
listStorageSpacesResponse, err := gatewayClient.ListStorageSpaces(ctx, &apiProvider.ListStorageSpacesRequest{
|
||||
Filters: []*apiProvider.ListStorageSpacesRequest_Filter{
|
||||
{
|
||||
Type: apiProvider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE,
|
||||
@@ -43,52 +41,15 @@ func PurgeTrashBin(executantID *apiUser.UserId, deleteBefore time.Time, spaceTyp
|
||||
}
|
||||
|
||||
for _, storageSpace := range listStorageSpacesResponse.StorageSpaces {
|
||||
var (
|
||||
err error
|
||||
impersonationID *apiUser.UserId
|
||||
storageSpaceReference = &apiProvider.Reference{
|
||||
ResourceId: storageSpace.GetRoot(),
|
||||
}
|
||||
)
|
||||
|
||||
switch SpaceType(storageSpace.GetSpaceType()) {
|
||||
case Personal:
|
||||
impersonationID = storageSpace.GetOwner().GetId()
|
||||
case Project:
|
||||
var permissionsMap map[string]*apiProvider.ResourcePermissions
|
||||
err := utils.ReadJSONFromOpaque(storageSpace.GetOpaque(), "grants", &permissionsMap)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
for id, permissions := range permissionsMap {
|
||||
if !permissions.Delete {
|
||||
continue
|
||||
}
|
||||
|
||||
impersonationID = &apiUser.UserId{
|
||||
OpaqueId: id,
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
if typ := storageSpace.GetSpaceType(); typ != "personal" && typ != "project" {
|
||||
// ignore spaces that are neither personal nor project
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
storageSpaceReference := &apiProvider.Reference{
|
||||
ResourceId: storageSpace.GetRoot(),
|
||||
}
|
||||
|
||||
if impersonationID == nil {
|
||||
return fmt.Errorf("can't impersonate space user for space: %s", storageSpace.GetId().GetOpaqueId())
|
||||
}
|
||||
|
||||
impersonatedCtx, _, err := utils.Impersonate(impersonationID, gatewayClient, machineAuthAPIKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
listRecycleResponse, err := gatewayClient.ListRecycle(impersonatedCtx, &apiProvider.ListRecycleRequest{Ref: storageSpaceReference})
|
||||
listRecycleResponse, err := gatewayClient.ListRecycle(ctx, &apiProvider.ListRecycleRequest{Ref: storageSpaceReference})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -99,7 +60,7 @@ func PurgeTrashBin(executantID *apiUser.UserId, deleteBefore time.Time, spaceTyp
|
||||
continue
|
||||
}
|
||||
|
||||
purgeRecycleResponse, err := gatewayClient.PurgeRecycle(impersonatedCtx, &apiProvider.PurgeRecycleRequest{
|
||||
purgeRecycleResponse, err := gatewayClient.PurgeRecycle(ctx, &apiProvider.PurgeRecycleRequest{
|
||||
Ref: storageSpaceReference,
|
||||
Key: recycleItem.Key,
|
||||
})
|
||||
|
||||
@@ -115,7 +115,7 @@ var _ = Describe("trash", func() {
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
|
||||
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(nil, genericError)
|
||||
|
||||
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
|
||||
err := task.PurgeTrashBin("service-user-id", now, task.Project, gatewaySelector, "")
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
It("throws an error if space listing fails", func() {
|
||||
@@ -123,45 +123,9 @@ var _ = Describe("trash", func() {
|
||||
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(authenticateResponse, nil)
|
||||
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(nil, genericError)
|
||||
|
||||
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
|
||||
err := task.PurgeTrashBin("service-user-id", now, task.Project, gatewaySelector, "")
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
It("throws an error if a personal space user can't be impersonated", func() {
|
||||
listStorageSpacesResponse.StorageSpaces = []*apiProvider.StorageSpace{personalSpace}
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
|
||||
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(authenticateResponse, nil)
|
||||
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(listStorageSpacesResponse, nil)
|
||||
|
||||
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
|
||||
Expect(err).To(MatchError(errors.New("can't impersonate space user for space: personal")))
|
||||
})
|
||||
It("throws an error if a project space user can't be impersonated", func() {
|
||||
listStorageSpacesResponse.StorageSpaces = []*apiProvider.StorageSpace{projectSpace}
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
|
||||
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(authenticateResponse, nil)
|
||||
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(listStorageSpacesResponse, nil)
|
||||
|
||||
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
|
||||
Expect(err).To(MatchError(errors.New("can't impersonate space user for space: project")))
|
||||
})
|
||||
It("throws an error if a project space has no user with delete permissions", func() {
|
||||
listStorageSpacesResponse.StorageSpaces = []*apiProvider.StorageSpace{projectSpace}
|
||||
projectSpace.Opaque.Map = map[string]*apiTypes.OpaqueEntry{
|
||||
"grants": {
|
||||
Value: MustMarshal(map[string]*apiProvider.ResourcePermissions{
|
||||
"admin": {
|
||||
Delete: false,
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(getUserResponse, nil)
|
||||
gatewayClient.On("Authenticate", mock.Anything, mock.Anything).Return(authenticateResponse, nil)
|
||||
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(listStorageSpacesResponse, nil)
|
||||
|
||||
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
|
||||
Expect(err).To(MatchError(errors.New("can't impersonate space user for space: project")))
|
||||
})
|
||||
It("only deletes items older than the specified period", func() {
|
||||
var (
|
||||
recycleItems = map[string][]*apiProvider.RecycleItem{
|
||||
@@ -231,7 +195,7 @@ var _ = Describe("trash", func() {
|
||||
}, nil,
|
||||
)
|
||||
|
||||
err := task.PurgeTrashBin(user.Id, now, task.Project, gatewaySelector, "")
|
||||
err := task.PurgeTrashBin("service-user-id", now, task.Project, gatewaySelector, "")
|
||||
Expect(err).To(BeNil())
|
||||
Expect(recycleItems["personal"]).To(HaveLen(2))
|
||||
Expect(recycleItems["project"]).To(HaveLen(2))
|
||||
|
||||
Reference in New Issue
Block a user