Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
package cloud.katta.cli.commands.hub.storageprofile;

import cloud.katta.cli.commands.hub.storageprofile.aws.AWS;
import cloud.katta.cli.commands.hub.storageprofile.minio.MinIO;
import picocli.CommandLine;

@CommandLine.Command(name = "storageprofile", subcommands = {
ArchiveStorageProfile.class,
AWS.class,
MinIO.class,
CommandLine.HelpCommand.class
},
description = "Configure Storage Location", mixinStandardHelpOptions = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2026 shift7 GmbH. All rights reserved.
*/

package cloud.katta.cli.commands.hub.storageprofile.minio;

import picocli.CommandLine;

@CommandLine.Command(name = "minio", subcommands = {
MinioSTSStorageProfile.class,
CommandLine.HelpCommand.class
},
description = "Setup MinIO Storage Provider Integration", mixinStandardHelpOptions = true)
public class MinIO {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2026 shift7 GmbH. All rights reserved.
*/

package cloud.katta.cli.commands.hub.storageprofile.minio;

import java.util.List;
import java.util.UUID;

import cloud.katta.cli.commands.hub.storageprofile.AbstractStorageProfile;
import cloud.katta.client.ApiException;
import cloud.katta.client.api.StorageProfileResourceApi;
import cloud.katta.client.model.Protocol;
import cloud.katta.client.model.S3SERVERSIDEENCRYPTION;
import cloud.katta.client.model.S3STORAGECLASSES;
import cloud.katta.client.model.StorageProfileS3STSDto;
import picocli.CommandLine;

/**
* Uploads a storage profile to Katta Server for use with MinIO STS. Requires MinIO STS setup.
* <p>
* Unlike AWS, MinIO does not support role chaining (AssumeRole with tagged session).
* Therefore {@code stsRoleAccessBucketAssumeRoleTaggedSession} and {@code stsSessionTag}
* are intentionally left {@code null}.
* <p>
* MinIO uses the {@code ${jwt:client_id}} policy variable to scope bucket access per vault.
* <p>
* See also: <a href="https://github.com/shift7-ch/katta-docs/blob/main/SETUP_KATTA_SERVER.md#minio">katta docs</a>.
*/
@CommandLine.Command(name = "sts",
description = "Upload storage profile for MinIO STS.",
showDefaultValues = true,
mixinStandardHelpOptions = true)
public class MinioSTSStorageProfile extends AbstractStorageProfile {

@CommandLine.Option(names = {"--endpointUrl"}, description = "MinIO endpoint URL (S3 API). Example: \"https://minio.example.com\"", required = true)
String endpointUrl;

@CommandLine.Option(names = {"--port"}, description = "MinIO endpoint port.", defaultValue = "443")
Integer port;

@CommandLine.Option(names = {"--scheme"}, description = "URL scheme (https or http).", defaultValue = "https")
String scheme;

@CommandLine.Option(names = {"--bucketPrefix"}, description = "Bucket prefix for STS vaults.", defaultValue = "katta-")
String bucketPrefix;

@CommandLine.Option(names = {"--stsRoleCreateBucket"}, description = "MinIO role ARN for bucket creation (from 'mc idp openid ls' for the cryptomator client).", required = true)
String stsRoleCreateBucket;

@CommandLine.Option(names = {"--stsRoleAccessBucket"}, description = "MinIO role ARN for bucket access (from 'mc idp openid ls' for the cryptomatorvaults client).", required = true)
String stsRoleAccessBucket;

public MinioSTSStorageProfile() {
}

@Override
protected void call(final StorageProfileResourceApi storageProfileResourceApi) throws ApiException {
final UUID uuid = UUID.fromString(null == this.uuid ? UUID.randomUUID().toString() : this.uuid);
final String hostname = endpointUrl.replaceFirst("^https?://", "");
storageProfileResourceApi.apiStorageprofileS3stsPost(new StorageProfileS3STSDto()
.id(uuid)
.name(null == name ? this.toString() : name)
.protocol(Protocol.S3_STS)
.archived(false)

// -- (1) S3 endpoint configuration for MinIO
.scheme(scheme)
.hostname(hostname)
.port(port)
.storageClass(S3STORAGECLASSES.STANDARD)
.withPathStyleAccessEnabled(true) // Required for MinIO

// -- (2) bucket creation
.bucketPrefix(bucketPrefix)
.region(region)
.regions(null == regions ? List.of(region) : regions)
.bucketEncryption(S3SERVERSIDEENCRYPTION.NONE)
.bucketVersioning(false) // MinIO versioning is optional
.bucketAcceleration(null) // Not supported by MinIO

// -- (3) STS roles from MinIO OIDC setup
.stsRoleCreateBucketClient(stsRoleCreateBucket)
.stsRoleCreateBucketHub(stsRoleCreateBucket)
.stsRoleAccessBucketAssumeRoleWithWebIdentity(stsRoleAccessBucket)

// -- (4) STS endpoint override for MinIO
.stsEndpoint(endpointUrl)

// -- (5) No role chaining for MinIO (AWS-only feature)
.stsRoleAccessBucketAssumeRoleTaggedSession(null)
.stsSessionTag(null)
);
System.out.println(storageProfileResourceApi.apiStorageprofileProfileIdGet(uuid));
}

@Override
public String toString() {
return String.format("MinIO (STS) Storage Profile %s", endpointUrl);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ public TemporaryAccessTokens assumeRoleWithWebIdentity(final OAuthTokens oauth,
final PreferencesReader settings = HostPreferencesFactory.get(bookmark);
final TemporaryAccessTokens tokens = super.assumeRoleWithWebIdentity(this.tokenExchange(oauth), settings.getProperty(S3AssumeRoleProtocol.S3_ASSUMEROLE_ROLEARN_WEBIDENTITY));
if(StringUtils.isNotBlank(settings.getProperty(S3AssumeRoleProtocol.S3_ASSUMEROLE_ROLEARN_TAG))) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stsRoleAccessBucketAssumeRoleTaggedSession setting in the storage profile configuration is mapped to the S3AssumeRoleProtocol.S3_ASSUMEROLE_ROLEARN_TAG setting and should be already null as shown above in the CLI setup. Thus the additional check for the STS endpoint is redundant.

// Role chaining with session tags is only supported by AWS, not MinIO
if(!StringUtils.equals(new S3Protocol().getSTSEndpoint(), bookmark.getProtocol().getSTSEndpoint())) {
log.warn("Skip role chaining for non-AWS STS endpoint {}", bookmark.getProtocol().getSTSEndpoint());
return tokens;
}
log.debug("Assume role with temporary credentials {}", tokens);
// Assume role with previously obtained temporary access token
final String key = HostPreferencesFactory.get(bookmark).getProperty("s3.assumerole.rolearn.tag.vaultid.key");
Expand Down