diff --git a/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml index 4a9ba1e33081..2d28ce4bfcc4 100644 --- a/deploy/charts/rook-ceph/templates/resources.yaml +++ b/deploy/charts/rook-ceph/templates/resources.yaml @@ -10053,6 +10053,34 @@ spec: items: type: string type: array + auth: + description: The authentication configuration + nullable: true + properties: + keystone: + description: KeystoneSpec represents the Keystone authentication configuration of a Ceph Object Store Gateway + nullable: true + properties: + acceptedRoles: + items: + type: string + type: array + implicitTenants: + type: string + revocationInterval: + type: integer + serviceUserSecretName: + type: string + tokenCacheSize: + type: integer + url: + type: string + required: + - acceptedRoles + - serviceUserSecretName + - url + type: object + type: object dataPool: description: The data pool settings nullable: true @@ -11294,6 +11322,31 @@ spec: preservePoolsOnDelete: description: Preserve pools on object store deletion type: boolean + protocols: + description: The protocol specification + nullable: true + properties: + s3: + description: The spec for S3 + nullable: true + properties: + authUseKeystone: + type: boolean + enabled: + type: boolean + type: object + swift: + description: The spec for S3 + nullable: true + properties: + accountInUrl: + type: boolean + urlPrefix: + type: string + versioningEnabled: + type: boolean + type: object + type: object security: description: Security represents security settings nullable: true @@ -11619,6 +11672,19 @@ spec: store: description: The store the user will be created in type: string + subUsers: + items: + properties: + access: + type: string + name: + type: string + required: + - access + - name + type: object + nullable: true + type: array type: object status: description: ObjectStoreUserStatus represents the status Ceph Object Store Gateway User diff --git a/deploy/examples/crds.yaml b/deploy/examples/crds.yaml index 5b3783a8490b..323cbb0d191d 100644 --- a/deploy/examples/crds.yaml +++ b/deploy/examples/crds.yaml @@ -10044,6 +10044,34 @@ spec: items: type: string type: array + auth: + description: The authentication configuration + nullable: true + properties: + keystone: + description: KeystoneSpec represents the Keystone authentication configuration of a Ceph Object Store Gateway + nullable: true + properties: + acceptedRoles: + items: + type: string + type: array + implicitTenants: + type: string + revocationInterval: + type: integer + serviceUserSecretName: + type: string + tokenCacheSize: + type: integer + url: + type: string + required: + - acceptedRoles + - serviceUserSecretName + - url + type: object + type: object dataPool: description: The data pool settings nullable: true @@ -11285,6 +11313,31 @@ spec: preservePoolsOnDelete: description: Preserve pools on object store deletion type: boolean + protocols: + description: The protocol specification + nullable: true + properties: + s3: + description: The spec for S3 + nullable: true + properties: + authUseKeystone: + type: boolean + enabled: + type: boolean + type: object + swift: + description: The spec for S3 + nullable: true + properties: + accountInUrl: + type: boolean + urlPrefix: + type: string + versioningEnabled: + type: boolean + type: object + type: object security: description: Security represents security settings nullable: true @@ -11609,6 +11662,19 @@ spec: store: description: The store the user will be created in type: string + subUsers: + items: + properties: + access: + type: string + name: + type: string + required: + - access + - name + type: object + nullable: true + type: array type: object status: description: ObjectStoreUserStatus represents the status Ceph Object Store Gateway User diff --git a/design/ceph/object/swift-and-keystone-integration.md b/design/ceph/object/swift-and-keystone-integration.md index 27717ade5093..3a27938b8ab7 100644 --- a/design/ceph/object/swift-and-keystone-integration.md +++ b/design/ceph/object/swift-and-keystone-integration.md @@ -80,11 +80,11 @@ Annotations: options](https://docs.ceph.com/en/octopus/radosgw/config-ref/#keystone-settings), the corresponding RGW option is formed by prefixing it with `rgw_keystone_` and replacing upper case letters by their lower case - letter followed by an underscore. E.g. `tokenCacheSize` maps to + letter preceded by an underscore. E.g. `tokenCacheSize` maps to `rgw_keystone_token_cache_size`. * `[2]` These settings are required in the `keystone` section if present. -* `[1]` The name of the secret containing the credentials for the +* `[3]` The name of the secret containing the credentials for the service user account used by RGW. It has to be in the same namespace as the object store resource. @@ -173,12 +173,12 @@ Annotations: options](https://docs.ceph.com/en/octopus/radosgw/config-ref/#swift-settings), the corresponding RGW option is formed by prefixing it with `rgw_swift_` and replacing upper case letters by their lower case - letter followed by an underscore. E.g. `urlPrefix` maps to + letter preceded by an underscore. E.g. `urlPrefix` maps to `rgw_swift_url_prefix`. They are optional. If not given, the defaults of the corresponding RGW option apply. -The access to the Swift API is granted by creating a subuser of an RGW -user. While commonly the access is granted via projects +Access to the Swift API is granted by creating a subuser of an RGW +user. While commonly access is granted via projects mapped from Keystone, explicit creation of subusers is supported by extending the `cephobjectstoreuser` resource with a new optional section `spec.subUsers`: diff --git a/pkg/apis/ceph.rook.io/v1/spec_test.go b/pkg/apis/ceph.rook.io/v1/spec_test.go index 3bbbe6142989..2875bf5520a5 100644 --- a/pkg/apis/ceph.rook.io/v1/spec_test.go +++ b/pkg/apis/ceph.rook.io/v1/spec_test.go @@ -92,3 +92,104 @@ storage: assert.Equal(t, expectedSpec, clusterSpec) } + +func newTrue() *bool { + t := true + return &t +} + +func newFalse() *bool { + t := false + return &t +} + +func newInt(val int) *int { + return &val +} + +func newString(val string) *string { + return &val +} + +func TestObjectStoreSpecMarhsalSwiftAndKeystone(t *testing.T) { + // Assert that the new ObjectStoreSpec fields specified in are correctly parsed + specYaml := []byte(` +auth: + keystone: + url: https://keystone:5000/ + acceptedRoles: ["_member_", "service", "admin"] + implicitTenants: swift + tokenCacheSize: 1000 + revocationInterval: 1200 + serviceUserSecretName: rgw-service-user +protocols: + swift: + accountInUrl: true + urlPrefix: /example + versioningEnabled: false + s3: + enabled: false + authUseKeystone: true +`) + rawJSON, err := yaml.ToJSON(specYaml) + assert.Nil(t, err) + fmt.Printf("rawJSON: %s\n", string(rawJSON)) + + // unmarshal the JSON into a strongly typed storage spec object + var objectStoreSpec ObjectStoreSpec + err = json.Unmarshal(rawJSON, &objectStoreSpec) + assert.Nil(t, err) + + // the unmarshalled storage spec should equal the expected spec below + expectedSpec := ObjectStoreSpec{ + Auth: AuthSpec{ + Keystone: &KeystoneSpec{ + Url: "https://keystone:5000/", + AcceptedRoles: []string{"_member_", "service", "admin"}, + ImplicitTenants: "swift", + TokenCacheSize: newInt(1000), + RevocationInterval: newInt(1200), + ServiceUserSecretName: "rgw-service-user", + }, + }, + Protocols: ProtocolSpec{ + S3: &S3Spec{ + Enabled: newFalse(), + AuthUseKeystone: newTrue(), + }, + Swift: &SwiftSpec{ + AccountInUrl: newTrue(), + UrlPrefix: newString("/example"), + VersioningEnabled: newFalse(), + }, + }, + } + + assert.Equal(t, expectedSpec, objectStoreSpec) +} + +func TestObjectStoreUserSpecMarhsalSubuser(t *testing.T) { + // Assert that the new ObjectStoreUserSpec fields specified in parse + specYaml := []byte(` +subUsers: +- name: swift + access: full +`) + rawJSON, err := yaml.ToJSON(specYaml) + assert.Nil(t, err) + fmt.Printf("rawJSON: %s\n", string(rawJSON)) + + // unmarshal the JSON into a strongly typed storage spec object + var objectStoreUserSpec ObjectStoreUserSpec + err = json.Unmarshal(rawJSON, &objectStoreUserSpec) + assert.Nil(t, err) + + // the unmarshalled storage spec should equal the expected spec below + expectedSpec := ObjectStoreUserSpec{ + Subusers: []SubuserSpec{ + {Name: "swift", Access: "full"}, + }, + } + + assert.Equal(t, expectedSpec, objectStoreUserSpec) +} diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go index baf337effa92..0c3598c1f0c8 100755 --- a/pkg/apis/ceph.rook.io/v1/types.go +++ b/pkg/apis/ceph.rook.io/v1/types.go @@ -1379,6 +1379,16 @@ type ObjectStoreSpec struct { // +nullable Gateway GatewaySpec `json:"gateway"` + // The protocol specification + // +optional + // +nullable + Protocols ProtocolSpec `json:"protocols,omitempty"` + + // The authentication configuration + // +optional + // +nullable + Auth AuthSpec `json:"auth,omitempty"` + // The multisite info // +optional // +nullable @@ -1528,6 +1538,59 @@ type EndpointAddress struct { Hostname string `json:"hostname,omitempty" protobuf:"bytes,3,opt,name=hostname"` } +// ProtocolSpec represents a Ceph Object Store protocol specification +type ProtocolSpec struct { + // The spec for S3 + // +optional + // +nullable + S3 *S3Spec `json:"s3,omitempty"` + + // The spec for S3 + // +optional + // +nullable + Swift *SwiftSpec `json:"swift"` +} + +// S3Spec represents Ceph Object Store specification for the S3 API +type S3Spec struct { + Enabled *bool `json:"enabled,omitempty"` + AuthUseKeystone *bool `json:"authUseKeystone,omitempty"` +} + +// S3Spec represents Ceph Object Store specification for the Swift API +type SwiftSpec struct { + AccountInUrl *bool `json:"accountInUrl,omitempty"` + UrlPrefix *string `json:"urlPrefix,omitempty"` + VersioningEnabled *bool `json:"versioningEnabled,omitempty"` +} + +// AuthSpec represents the authentication protocol configuration of a Ceph Object Store Gateway +type AuthSpec struct { + // +optional + // +nullable + Keystone *KeystoneSpec `json:"keystone,omitempty"` +} + +// KeystoneSpec represents the Keystone authentication configuration of a Ceph Object Store Gateway +type KeystoneSpec struct { + Url string `json:"url"` + ServiceUserSecretName string `json:"serviceUserSecretName"` + AcceptedRoles []string `json:"acceptedRoles"` + ImplicitTenants ImplicitTenantSetting `json:"implicitTenants,omitempty"` + TokenCacheSize *int `json:"tokenCacheSize,omitempty"` + RevocationInterval *int `json:"revocationInterval,omitempty"` +} + +type ImplicitTenantSetting string + +const ( + ImplicitTenantSwift ImplicitTenantSetting = "swift" + ImplicitTenantS3 ImplicitTenantSetting = "s3" + ImplicitTenantTrue ImplicitTenantSetting = "true" + ImplicitTenantFalse ImplicitTenantSetting = "false" + ImplicitTenantDefault ImplicitTenantSetting = "" +) + // ZoneSpec represents a Ceph Object Store Gateway Zone specification type ZoneSpec struct { // RGW Zone the Object Store is in @@ -1615,6 +1678,9 @@ type ObjectStoreUserSpec struct { // The namespace where the parent CephCluster and CephObjectStore are found // +optional ClusterNamespace string `json:"clusterNamespace,omitempty"` + // +optional + // +nullable + Subusers []SubuserSpec `json:"subUsers,omitemtpy"` } // Additional admin-level capabilities for the Ceph object store user @@ -1702,6 +1768,21 @@ type ObjectUserQuotaSpec struct { MaxObjects *int64 `json:"maxObjects,omitempty"` } +type SubuserSpec struct { + Name string `json:"name"` + Access AccessSpec `json:"access"` +} + +type AccessSpec string + +const ( + AccessSpecFull AccessSpec = "full" + AccessSpecRead AccessSpec = "read" + AccessSpecWrite AccessSpec = "write" + AccessSpecReadWrite AccessSpec = "readwrite" +) + +// CephObjectRealm represents a Ceph Object Store Gateway Realm // +genclient // +genclient:noStatus // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/operator/ceph/config/monstore.go b/pkg/operator/ceph/config/monstore.go index 96dd1f7f77d1..e5533cb46620 100644 --- a/pkg/operator/ceph/config/monstore.go +++ b/pkg/operator/ceph/config/monstore.go @@ -58,7 +58,7 @@ type Option struct { // SetIfChanged sets a config in the centralized mon configuration database if the config has // changed value. -// https://docs.ceph.com/docs/master/rados/configuration/ceph-conf/#monitor-configuration-database +// https://docs.ceph.com/en/latest/rados/configuration/ceph-conf/#monitor-configuration-database // // There is a bug through at least Ceph v18 where `ceph config get global