Skip to content

Commit

Permalink
Feature s3 v4 auth support (#220)
Browse files Browse the repository at this point in the history
* AWS signature V4
* Added awsSignatureV4 flag to ecs connection settings. Chart values refactoring - fixing #151.
* Bump Spring Boot version to 2.6.7
Co-authored-by: Mamedov <[email protected]>
Co-authored-by: Rogalchuk, Vyacheslav <[email protected]>
  • Loading branch information
Mansur51-hub authored Apr 21, 2022
1 parent b73d5ce commit 8a9be9a
Show file tree
Hide file tree
Showing 16 changed files with 133 additions and 138 deletions.
5 changes: 2 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
buildscript {
ext {
springBootVersion = '2.6.6'
springBootVersion = '2.6.7'
}
repositories {
mavenCentral()
Expand Down Expand Up @@ -45,8 +45,7 @@ dependencies {
implementation(group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.16.0')
implementation(group: 'org.apache.logging.log4j', name: 'log4j-to-slf4j', version: '2.16.0')


implementation(group: 'com.emc.ecs', name: 'object-client', version: '3.1.3') {
implementation(group: 'com.emc.ecs', name: 'object-client', version: '3.4.0') {
exclude module: "slf4j-log4j12"
exclude module: "jsr311-api"
}
Expand Down
19 changes: 3 additions & 16 deletions charts/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,11 @@ data:
---
broker:
prefix: {{ .Values.prefix }}
{{- if eq (default "ECS" .Values.brokerMode) "ECS" }}
object-endpoint: {{ .Values.api.endpoint }}
management-endpoint: {{ .Values.ecsConnection.endpoint }}
management-endpoint: {{ .Values.ecsConnection.managementEndpoint }}
object-endpoint: {{ .Values.ecsConnection.s3endpoint }}
namespace: {{ .Values.namespace }}
replication-group: {{ .Values.replicationGroup }}
{{- end}}
{{- if eq (default "ECS" .Values.brokerMode) "objectscale" }}
apiType: "objectscale"
accountId: {{ .Values.objectscale.account.id }}
objectscale:
id: {{ .Values.objectscale.id }}
gatewayEndpoint: {{ .Values.objectscale.gatewayEndpoint }}
objectstore:
id: {{ .Values.objectstore.id }}
name: {{ .Values.objectstore.name }}
managementEndpoint: {{ .Values.objectstore.managementEndpoint }}
s3Endpoint: {{ .Values.objectstore.s3Endpoint }}
{{- end}}
awsSignatureV4: {{ default false .Values.ecsConnection.awsSignatureV4 }}
{{- if .Values.certificate }}
certificate: {{ toYaml .Values.certificate | indent 6 }}
{{- end }}
Expand Down
32 changes: 4 additions & 28 deletions charts/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,46 +29,22 @@ spec:
valueFrom:
secretKeyRef:
key: username
name: {{ .Values.api.name }}-auth
name: {{ .Values.api.secretName }}
- name: "SECURITY_USER_PASSWORD"
valueFrom:
secretKeyRef:
key: password
name: {{ .Values.api.name }}-auth
{{- if eq (default "ECS" .Values.brokerMode) "ECS" }}
name: {{ .Values.api.secretName }}
- name: "BROKER_USERNAME"
valueFrom:
secretKeyRef:
name: {{ .Values.ecsConnection.name }}-auth
name: {{ .Values.ecsConnection.secretName }}
key: username
- name: "BROKER_PASSWORD"
valueFrom:
secretKeyRef:
name: {{ .Values.ecsConnection.name }}-auth
name: {{ .Values.ecsConnection.secretName }}
key: password
{{- end }}
{{- if eq (default "ECS" .Values.brokerMode) "objectscale" }}
- name: "BROKER_USERNAME"
valueFrom:
secretKeyRef:
name: {{ .Values.objectscale.id }}-auth
key: username
- name: "BROKER_PASSWORD"
valueFrom:
secretKeyRef:
name: {{ .Values.objectscale.id }}-auth
key: password
- name: "BROKER_ACCESS_KEY"
valueFrom:
secretKeyRef:
name: {{ .Values.objectscale.id }}-account-key
key: accessKey
- name: "BROKER_SECRET_KEY"
valueFrom:
secretKeyRef:
name: {{ .Values.objectscale.id }}-account-key
key: secretKey
{{- end }}
volumes:
- name: config-volume
configMap:
Expand Down
26 changes: 2 additions & 24 deletions charts/templates/secrets.yaml
Original file line number Diff line number Diff line change
@@ -1,44 +1,22 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.api.name }}-auth
name: {{ .Values.api.secretName }}
data:
username: {{ default "" .Values.api.username | b64enc | quote }}
password: {{ default "" .Values.api.password | b64enc | quote }}

{{- if eq (default "ECS" .Values.brokerMode) "ECS" }}
---

apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.ecsConnection.name }}-auth
name: {{ .Values.ecsConnection.secretName }}
data:
username: {{ default "" .Values.ecsConnection.username | b64enc | quote }}
password: {{ default "" .Values.ecsConnection.password | b64enc | quote }}
{{- end}}
{{- if eq (default "ECS" .Values.brokerMode) "objectscale" }}
---

apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.objectscale.id }}-auth
data:
username: {{ default "" .Values.objectscale.managementUser.name | b64enc | quote }}
password: {{ default "" .Values.objectscale.managementUser.password | b64enc | quote }}

---

apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.objectscale.id }}-account-key
data:
accessKey: {{ default "" .Values.objectscale.account.accessKey | b64enc | quote }}
secretKey: {{ default "" .Values.objectscale.account.secretKey | b64enc | quote }}

{{- end }}
{{ if .Values.serviceCatalog }}
---

Expand Down
48 changes: 16 additions & 32 deletions charts/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,33 @@

replicaCount: 1

namespace: "131118670375936839"
prefix: "kubetesting-"
# ECS replication group and namespace to use as default for broker repository and new services
replicationGroup: "ecstestdrivegeo"
namespace: "131118670375936839"

# Set to true if want to skip ssl validation errors
ignoreSslValidation: false
# Prefix all broker created buckets and users. Defaults to 'ecs-cf-broker-'
prefix: "kubetesting-"

# Management SSL Custom CA Trust Certificate
certificate: |-
# ECS Object API
api:
name: ecs-broker
namespace: default
endpoint: "https://object.ecstestdrive.com"
username: admin
password: ChangeMe
# Set to true if want to skip ssl validation errors
ignoreSslValidation: true

# ECS Management Endpoint
# ECS Management and Object Endpoints connection details
ecsConnection:
name: ecs-broker-connection
endpoint: "https://portal.ecstestdrive.com"
secretName: ecs-broker-connection # k8s secret name, used to store management API auth credentials
managementEndpoint: "https://portal.ecstestdrive.com"
username: <MANAGEMENT_USER>
password: <PASSWORD>
s3endpoint: "https://object.ecstestdrive.com"
awsSignatureV4: false # Use AWS signature V4 to authenticate S3 requests (use V2 if false)

## Objectscale
## to use service broker with objectstore instance, fill values and uncomment:
#brokerMode: objectscale
#objectscale:
# id: "osci1234567890abcdef"
# gatewayEndpoint: "https://10.20.30.40:21234"
# managementUser:
# name: "user1"
# password: "password1"
# account:
# id: "osai1234567890abcdef"
# accessKey: "abc111"
# secretKey: "secret"
#objectstore:
# id: "osti1234567890abcdef"
# name: "some-store-name"
# managementEndpoint: "https://10.20.30.41:31234"
# s3Endpoint: "https://10.20.30.42:41234"
# Broker API security
api:
secretName: ecs-broker-auth # k8s secret name, used to store broker API auth credentials
username: admin
password: ChangeMe

image:
repository: objectscale/ecs-service-broker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ public S3Client objectstoreS3Client(BrokerConfig config) throws URISyntaxExcepti
logger.info("Preparing S3 endpoint client: '{}', bucket '{}', account '{}', access key '{}'", repositoryEndpoint, bucket, accountId, userName);

S3Config s3Config = new S3Config(new URI(repositoryEndpoint))
.withUseV2Signer(!config.isAwsSignatureV4())
.withNamespace(accountId)
.withIdentity(userName)
.withSecretKey(repositorySecret);
Expand All @@ -196,6 +197,7 @@ public S3Client ecsS3Client(BrokerConfig config) throws URISyntaxException {
logger.info("Preparing S3 endpoint client: '{}', bucket '{}', repository username '{}'", repositoryEndpoint, bucket, userName);

S3Config s3Config = new S3Config(new URI(repositoryEndpoint))
.withUseV2Signer(!config.isAwsSignatureV4())
.withIdentity(userName)
.withSecretKey(repositorySecret);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class BrokerConfig {
private String nfsMountHost;
private String repositoryEndpoint;
private boolean useSsl;
private boolean awsSignatureV4 = false;
private boolean ignoreSslValidation;

private String repositorySecret;
Expand Down Expand Up @@ -261,9 +262,11 @@ public void setDefaultReclaimPolicy(String defaultReclaimPolicy) {
this.defaultReclaimPolicy = defaultReclaimPolicy;
}

public boolean isPathStyleAccess() {
return pathStyleAccess;
}
public boolean isPathStyleAccess() { return pathStyleAccess; }

public boolean isAwsSignatureV4() { return awsSignatureV4; }

public void setAwsSignatureV4(boolean awsSignatureV4) { this.awsSignatureV4 = awsSignatureV4; }

public void setPathStyleAccess(boolean pathStyleAccess) {
this.pathStyleAccess = pathStyleAccess;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.emc.ecs.servicebroker.model;

import org.codehaus.jackson.annotate.JsonProperty;

import com.fasterxml.jackson.annotation.JsonProperty;

public class ServiceTypeOption {
@JsonProperty("repository_service")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,9 @@ public UserSecretKey createBindingUser() throws EcsManagementClientException, IO

Map<String, Object> parameters = createRequest.getParameters();

String export = "";
List<String> permissions = null;
if (parameters != null) {
permissions = (List<String>) parameters.get(USER_PERMISSIONS);
export = (String) parameters.getOrDefault(VOLUME_EXPORT, null);
}

if (permissions == null) {
Expand All @@ -61,6 +59,10 @@ public UserSecretKey createBindingUser() throws EcsManagementClientException, IO
}

if (ecs.getBucketFileEnabled(bucket, namespace)) {
String export = "";
if (parameters != null) {
export = (String) parameters.getOrDefault(VOLUME_EXPORT, null);
}
volumeMounts = createVolumeExport(export, new URL(ecs.getObjectEndpoint()), bucket, namespace, parameters);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package com.emc.ecs.servicebroker.service;

import com.emc.ecs.management.sdk.*;
import com.emc.ecs.management.sdk.ManagementAPIConnection;
import com.emc.ecs.management.sdk.actions.*;
import com.emc.ecs.management.sdk.actions.iam.IAMUserAction;
import com.emc.ecs.management.sdk.model.*;
import com.emc.ecs.servicebroker.config.BrokerConfig;
import com.emc.ecs.servicebroker.config.CatalogConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,46 @@ public final class BucketExpirationAction {
private static final Logger logger = LoggerFactory.getLogger(BucketExpirationAction.class);
public static String RULE_PREFIX = "broker-lifecycle-rule-";

public static void update(BrokerConfig broker, String namespace, String bucketName, int days, List<LifecycleRule> currentRules) throws URISyntaxException {
public static void update(BrokerConfig brokerConfig, String namespace, String bucketName, int days, List<LifecycleRule> currentRules) throws URISyntaxException {
if (days < 0) {
throw new IllegalArgumentException("Invalid expiration days set on '" + bucketName + "' bucket: Expiration days could not be less then 0");
}
S3Client s3Client = generateS3Config(broker, namespace, bucketName);

LifecycleRule newRule = new LifecycleRule(RULE_PREFIX + UUID.randomUUID().toString(), '0' + bucketName, LifecycleRule.Status.Enabled)
.withExpirationDays(days);
LifecycleRule newRule = new LifecycleRule(
RULE_PREFIX + UUID.randomUUID().toString(), '0' + bucketName, LifecycleRule.Status.Enabled
).withExpirationDays(days);

S3Client s3Client = createS3Client(brokerConfig, namespace);

if (currentRules == null) {
logger.debug("Adding bucket lifecycle rule {}: expiration days = {}", newRule.getPrefix(), newRule.getExpirationDays());
s3Client.setBucketLifecycle(bucketName, new LifecycleConfiguration().withRules(newRule));
} else {
newRule.setPrefix(currentRules.size() + bucketName);
currentRules.add(newRule);
logger.debug("Adding bucket lifecycle rule {}: expiration days = {}", newRule.getPrefix(), newRule.getExpirationDays());
s3Client.setBucketLifecycle(bucketName, new LifecycleConfiguration().withRules(currentRules));
}
}

public static LifecycleConfiguration get(BrokerConfig broker, String namespace, String bucketName) throws URISyntaxException {
S3Client s3Client = generateS3Config(broker, namespace, bucketName);
public static LifecycleConfiguration get(BrokerConfig brokerConfig, String namespace, String bucketName) throws URISyntaxException {
S3Client s3Client = createS3Client(brokerConfig, namespace);

LifecycleConfiguration lifecycle;
try {
lifecycle = s3Client.getBucketLifecycle(bucketName);
} catch (S3Exception exception) {
logger.warn("Object user '{}' does not have Lifecycle Management policy on bucket '{}'", broker.getPrefixedUserName(), bucketName);
logger.warn("Object user '{}' does not have Lifecycle Management policy on bucket '{}'", brokerConfig.getPrefixedUserName(), bucketName);
return null;
}

return lifecycle;
}

public static void delete(BrokerConfig broker, String namespace, String bucketName, String ruleId, List<LifecycleRule> rules) throws URISyntaxException {
S3Client s3Client = generateS3Config(broker, namespace, bucketName);
public static void delete(BrokerConfig brokerConfig, String namespace, String bucketName, String ruleId, List<LifecycleRule> rules) throws URISyntaxException {
S3Client s3Client = createS3Client(brokerConfig, namespace);

for (LifecycleRule rule: rules) {
for (LifecycleRule rule : rules) {
if (rule.getId().equals(ruleId)) {
rules.remove(rule);
break;
Expand All @@ -69,13 +73,18 @@ public static void delete(BrokerConfig broker, String namespace, String bucketNa
}
}

private static S3Client generateS3Config(BrokerConfig broker, String namespace, String bucketName) throws URISyntaxException {
S3Config s3Config = new S3Config(new URI(broker.getRepositoryEndpoint()))
.withIdentity(broker.getPrefixedUserName())
.withSecretKey(broker.getRepositorySecret());
private static S3Client createS3Client(BrokerConfig brokerConfig, String namespace) throws URISyntaxException {
// TODO check objectscale config support here

S3Config s3Config = new S3Config(new URI(brokerConfig.getRepositoryEndpoint()))
.withUseV2Signer(!brokerConfig.isAwsSignatureV4())
.withIdentity(brokerConfig.getPrefixedUserName())
.withSecretKey(brokerConfig.getRepositorySecret());

if (namespace != null) {
s3Config.setNamespace(namespace);
}

return new S3JerseyClient(s3Config);
}
}
5 changes: 4 additions & 1 deletion src/test/java/com/emc/ecs/TestSuite.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.emc.ecs.management.sdk.actions.*;
import com.emc.ecs.management.sdk.actions.iam.IamUserActionTest;
import com.emc.ecs.servicebroker.config.BrokerConfig;
import com.emc.ecs.servicebroker.config.BrokerConfigTest;
import com.emc.ecs.servicebroker.config.CatalogConfigTest;
import com.emc.ecs.servicebroker.model.ServiceDefinitionProxyTest;
import com.emc.ecs.servicebroker.repository.ServiceInstanceBindingRepositoryTest;
Expand Down Expand Up @@ -44,7 +46,8 @@
BucketBindingWorkflowTest.class,
BucketInstanceWorkflowTest.class,
IamUserActionTest.class,
RemoteConnectionInstanceWorkflowTest.class
RemoteConnectionInstanceWorkflowTest.class,
BrokerConfigTest.class
})
public class TestSuite {

Expand Down
Loading

0 comments on commit 8a9be9a

Please sign in to comment.