Руководство прикладного разработчика#
Термины и определения#
Сокращение |
Полное наименование |
|---|---|
Ceph |
Масштабируемое хранилище с открытым исходным кодом, в основе которого лежит принцип объединения дисковых пространств серверов в единое объектное хранилище, что позволяет реализовать гибкую многократную псевдослучайную избыточность данных |
HTTP |
HyperText Transfer Protocol - протокол передачи гипертекста |
S3 |
Облачное хранилище данных |
RPC |
Remote Procedure Call - система удаленного вызова процедур |
АС |
Автоматизированная система |
ReplicaSet |
логическое объединение нескольких SDS кластеров в рамках выполняемой операции |
Context UUID |
уникальный идентификатор контекста в рамках приложения |
Системные требования#
Системное программное обеспечение описано в разделе «Системные требования» документа «Руководство по установке».
Подключение и конфигурирование#
Все ниже указанные манипуляции необходимо производить в файле конфигурации приложения application.yaml Значения необходимо переопределить в соответствии с вашими потребностями и окружением
Определение порта и точки входа в приложение#
server:
port: <value> # рекомендуемое значение: 8080
spring:
webflux:
base-path: <value> # рекомендуемое значение: /
Конфигурирование FSGW#
platform.file-storage-gateway:
version: <версия> # текущая версия: 2.0
swagger-ui: # опциональный раздел
enabled: <enabled> # true / false (по умолчанию, false)
storage.s3:
base-path: <path> # базовый path, запросы на который ожидает шлюз (по умолчанию: s3)
clusters: <описание cluster см. в соответствующем разделе>
replica-sets: <описание replica set см. в соответствующем разделе>
Добавление кластеров S3 для подключения#
<cluster alias>: # любой удобный для вас alias (будет указываться в рамках replica-set - см. ниже)
endpoint:
scheme: <scheme> # http / https
host: <host>
port: <port>
region: <region> # в случае Ceph ни на что не влияет
users: <описание user см. в соответствующем разделе>
s3-configuration: # опциональный раздел параметров
<описание s3 configuration см. в соответствующем разделе>
http-client-configuration: # опциональный раздел параметров
<описание http-client-configuration см. в соответствующем разделе>
Добавление пользователей для подключения к S3 кластерам#
Без использования Vault KV совместимого хранилища#
<user alias>: # любой удобный для вас alias (будет указываться в рамках replica-set - см. ниже)
access-key-id: ${environment parameter name for access key id}
secret-access-key: ${environment parameter name for secret access key}
С использованием Vault KV совместимого хранилища#
<user alias>: # любой удобный для вас alias (будет указываться в рамках replica-set - см. ниже)
access-key-id:
environment-variable-name: access-key
secret-access-key:
environment-variable-name: secret-key
access-key и secret-key - ключи из Vault KV совместимого хранилища, по которым будут проинициализированы поля
Параметры работы с S3 кластером#
s3-configuration: # опциональный раздел параметров
access-style: <value> # virtual-hosted–style / path-style (по умолчанию, path-style)
chunked-encoding: <value> # true / false (по умолчанию, false)
checksum-validation: <value> # true / false (по умолчанию, false)
Параметры клиента для подключения к S3 кластерам#
http-client-configuration: # опциональный раздел параметров
max-concurrency: <value> # по умолчанию: 128
connection-timeout: <value> # по умолчанию: 30s
read-timeout: <value> # по умолчанию: 30s
write-timeout: <value> # по умолчанию: 30s
Все таймауты указываются в стиле "simple" duration formatting.
Параметры ReplicaSet#
<replica set alias>: # любой удобный для вас alias (будет указываться в опциональном заголовке s3 запроса: x-amz-replica-set)
default: <value> # true / false (опциональный параметр, по умолчанию: false)
clusters:
<cluster 1 alias>: # один из тех, что уже был объявлен выше
user: <user 1 alias> # один из тех, что уже был объявлен выше
<cluster 2 alias>: # один из тех, что уже был объявлен выше
user: <user 2 alias> # один из тех, что уже был объявлен выше
sync-replication:
min-success-replication-factor: <value> # значение на отрезке: [1, clusters.size]
cipher: # опциональный раздел параметров
<описание cipher см. в соответствующем разделе>
signature: # опциональный раздел параметров
<описание signature см. в соответствующем разделе>
Не более чем один replica-set может иметь признак
default: true.
Параметры шифрования (опционально)#
cipher: # опциональный раздел параметров (ниже указаны значения, используемые по умолчанию)
block-cipher-suites: # криптонаборы, базирующиеся на блочных алгоритмах шифрования
AES128:
mode: GCM
padding: NoPadding
AES256:
mode: GCM
padding: NoPadding
GOST3412-2015:
mode: GCM
padding: NoPadding
stream-cipher-suites: # криптонаборы, базирующиеся на потоковых алгоритмах шифрования
ChaCha20:
mode: Poly1305
Параметры работы с подписью (опционально)#
При интеграции с Vault KV совместимом хранилище бинарные секреты должны быть закодированы в base64 и размещены в Key-Value хранилище Vault KV совместимом хранилищем
signature: # опциональный раздел параметров (в его отсутствие функционал работы с ЭП будет недоступен)
key-store-suites:
<key store alias>:
type: <value> # JKS / JCEKS / PKCS12
location: <путь до файла key store>
password: ${наименование переменной окружения, хранящей пароль от key store} # опциональный параметр
private-key:
alias: <alias, с которым сохранен приватный ключ в key store>
password: ${наименование переменной окружения, хранящей пароль от private key в key store}
certificate-aliases:
- <alias, с которым в key store сохранен публичный ключ, парный к текущему приватному>
- <alias, с которым в key store сохранен публичный ключ, парный к предыдущему приватному> # если таковой имелся
Конфигурирование crypto-web сервиса (опционально)#
platform:
utils:
crypto: # опциональный раздел параметров
web-service:
base-path: <path> # базовый path, запросы на который ожидает веб крипто-сервис (по умолчанию: crypto)
cipher-suites: # опциональный раздел параметров (в его отсутствие будут использованы параметры шифронаборов по умолчанию)
block-cipher-suites: <описание block-cipher-suites см. ниже>
stream-cipher-suites: <описание stream-cipher-suites см. ниже>
signature-suites: # опциональный раздел параметров (в его отсутствие функционал работы с ЭП будет недоступен)
key-store-suites: <описание key-store-suites см. ниже>
Конфигурирование Platform V Audit SE#
platform.utils:
audit:
writer: REST
rest-writer:
base-url: <audit service url>
Расширение событий context UUID (опционально)#
platform:
utils:
audit:
meta-model:
context-uuid:
value-source:
http-header: <some-header-name> # заголовок входящего http-запроса, значение которого будет использовано в качестве audit context uuid
Добавление параметров событий Platform V Audit SE (опционально).#
Если требуется добавить произвольные параметры к событиям аудита, то необходимо явным образом указать это в параметрах конфигурации.
platform:
utils:
audit:
meta-model:
additional-event-parameters:
SOME_ADDITIONAL_PARAM_1: # код параметра аудита, которым будет обогащен каждый запрос аудита
value-source:
http-header: <some-additional-param-header-name-1> # заголовок входящего http-запроса, значение которого будет использовано в параметре
localization:
rus: "ваше описание параметра"
eng: "your parameter description"
SOME_ADDITIONAL_PARAM_2: # код параметра аудита, которым будет обогащен каждый запрос аудита
value-source:
http-header: <some-additional-param-header-name-2> # заголовок входящего http-запроса, значение которого будет использовано в параметре
localization:
rus: "ваше описание параметра"
eng: "your parameter description"
Конфигурирование мониторинга#
По умолчанию все входные точки пакета Spring Boot Actuator включены метрики мониторинга в формате Prometheus и доступны по пути:
/actuator/prometheus
Конфигурирование журналирования#
Компонент поддерживает работу с двумя видами журналирования:
локальное - пишет в локальный журнал. Конфигурируется секцией
localразделаlogging.startup-parametersвнешнее - отправка записей во внешнюю систему (продукт Platform V Monitor OPM компонент LOGA). Конфигурируется секцией
remoteразделаlogging.startup-parameters
По умолчанию (если не указывать никаких параметров), журналирование активно, пишется в локальный файл. При необходимости журналирование можно отключить явно или изменить уровни логирования для отдельных пакетов:
platform.utils:
logging:
startup-parameters:
local:
enabled: false # true
level:
root: INFO # DEBUG / INFO / WARN / ERROR
name: # указать java пакеты, либо оставить пусто
remote:
level:
root: INFO
name:
appender:
kafka:
enabled: true
connection:
topic: FSGW.LOGGER
producer:
"[bootstrap.servers]": localhost:9094
Интеграция с Vault KV совместимое хранилище#
Предварительно необходимые секреты должны быть размещены в KV хранилище Vault KV совместимое хранилище
FSGW использует стандартные механизмы конфигурирования
Приведенный пример актуален для OSE/k8s окружения, предварительно должен быть размещен SA с правами доступа в Vault KV совместимое хранилище
Добавить секцию для подключения к Vault KV совместимое хранилище
spring:
config:
import: optional:vault://DEV_DZO/A/DEV/FSGW/KV/S3-IFT #имя секрета в рамках KV хранилища
cloud:
vault:
enable: true
kubernetes:
kubernetes-path: os/stands # путь авторизации для конкретного инстанса Vault KV совместимое хранилище
role: role-ga-secman-fex-users # имя роли доступа
authentication: KUBERNETES # тип аутентификации
namespace: DEV # имя неймспейса конкретного инстанса Vault KV совместимое хранилище
transitEngineCacheTTL: 30S #время кеширования ключа в режиме fsgw-tse-key, по умолчанию 0.
transitEngineCacheSize: 100 #размер кеша, по умолчанию 0
config.lifecycle: # параметры обновления конфигурации
enabled: true
min-renewal: 10s
expiry-threshold: 10s
uri: http://somedomain.ru #URL до конкретного инстанса Vault KV совместимое хранилище
Миграция на текущую версию#
Дополнительных действий для миграции не требуется, т.к. FSGW реализует поведение согласно протоколу S3 и является прозрачным S3 шлюзом для файловых интеграций.
Быстрый старт#
Настройте сервис согласно разделу "Подключение и конфигурирование".
Запустите приложение командой
java --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -XX:MaxRAMPercentage=90.0 -Dio.netty.tryReflectionSetAccessible=true -Dspring.config.additional-location="file:/opt/conf/file-storage-gateway/file-storage-gateway-config.yml" -jar /opt/file-storage-gateway/file-storage-gateway.jar.Выполните GET-запрос по адресу
http request /actuator/health.Получите ответ со статусом 200 и содержимым:
{ "status":"UP", "components":{ "diskSpace":{ "status":"UP", "details":{ "total":<значение вашей ФС>, "free":<значение вашей ФС>, "threshold":<значение вашей ФС>, "exists":true } }, "ping":{ "status":"UP" } } }
Где:
file-storage-gateway.jar- файл приложения./opt/conf/file-storage-gateway/file-storage-gateway-config.yml- путь до файла конфигурации.
Использование программного компонента#
File Storage Gateway является прозрачным шлюзом S3, который имитирует шифрование на стороне сервера с использованием клиентского ключа(SSE-C) и подписи (открепленная подпись). Реализует следующий список операций:
ListBuckets
HeadBucket
CreateBucket
DeleteBucket
PutObject
GetObject
HeadObject
CopyObject
DeleteObject
ListObjects
CreateMultipartUpload
UploadPart
AbortMultipartUpload
CompleteMultipartUpload
Для работы с FSGW рекомендуется использование Amazon S3 SDK.
Далее рассмотрим работу с S3 SDK на примере Amazon S3 SDK for Java 2.0.
Подключите зависимость#
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.X.Y</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
<version>2.X.Y</version>
</dependency>
Не рекомендуется использовать Amazon S3 SDK for Java 1.0.
Все дальнейшие примеры будут базироваться на использовании Amazon S3 SDK v2.
Настройте клиента#
@Configuration
public class S3AsyncClientConfiguration {
@Bean
public S3AsyncClient s3AsyncGatewayClient() {
return S3AsyncClient.builder()
.region(Region.of("FSGW"))
.httpClient(buildSdkAsyncHttpClient())
.endpointOverride(getS3GatewayEndpoint())
.serviceConfiguration(getS3Configuration())
.credentialsProvider(getAwsCredentialsProvider())
.overrideConfiguration(buildClientOverrideConfiguration())
.build();
}
private S3Configuration getS3Configuration() {
return S3Configuration.builder()
.pathStyleAccessEnabled(true)
.chunkedEncodingEnabled(false)
.checksumValidationEnabled(false)
.build();
}
public AwsCredentialsProvider getAwsCredentialsProvider() {
return AnonymousCredentialsProvider.create();
}
private URI getS3GatewayEndpoint() {
return UriComponentsBuilder.newInstance()
.scheme("http")
.host("fsgwHost") // в случае sidecar - "localhost", в случае service - адрес сервиса в k8s
.port(fsgwPort) // по умолчанию, 8080
.path("fsgwPath") // по умолчанию, "/s3"
.build()
.toUri();
}
private SdkAsyncHttpClient buildSdkAsyncHttpClient() {
return NettyNioAsyncHttpClient.builder()
.writeTimeout(Duration.ofSeconds(30))
.readTimeout(Duration.ofSeconds(30))
.connectionTimeout(Duration.ofSeconds(1))
.maxConcurrency(128)
.buildWithDefaults(AttributeMap.builder()
.put(SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES, true)
.build()
);
}
private ClientOverrideConfiguration buildClientOverrideConfiguration() {
return ClientOverrideConfiguration.builder()
.retryPolicy(RetryPolicy.none())
.build();
}
}
Выполните запрос к компоненту FSGW#
@Service
public class SomeService {
@Autowired
private S3AsyncClient s3AsyncGatewayClient;
public void putObject(String bucket, String objectKey, Publisher<ByteBuffer> objectContent, long objectContentLength) {
CompletableFuture<PutObjectResponse> putObjectResponseFuture = s3AsyncGatewayClient.putObject(
PutObjectRequest.builder()
.bucket(bucket)
.key(objectKey)
.contentLength(objectContentLength)
.build(),
AsyncRequestBody.fromPublisher(objectContent)
);
/*...*/
if (!putObjectResponse.sdkHttpResponse().isSuccessful()) {
// ToDo: do something
}
// ToDo: do something
}
}
Добавьте к запросу метаданные#
PutObjectRequest.builder()
.metadata(Map.of("ключ вашей меты", "значение"))
// другие поля
.build()
Используйте конкретный ReplicaSet#
PutObjectRequest.builder()
.overrideConfiguration(builder -> {
builder.putHeader("x-amz-replica-set", "alias replica-set из файла конфигурации");
})
// другие поля
.build()
Зашифруйте содержимое#
//В случае самостоятельной генерации ключа
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
byte[] key = keyGenerator.generateKey().getEncoded();
//В случае получения ключа от HashiCorp Vault в составе FSGW
HttpRequest httpRequest = HttpRequest.newBuilder().uri(String.format("%s/generate/cipher/key?algorithm=AES256", "http://8080/crypto/")).build();
HttpResponse<byte[]> httpResponse = HttpClient.newHttpClient().send(httpRequest, HttpResponse.BodyHandlers.ofByteArray());
byte[] key = httpResponse.body();
//Непосредственно подстановка ключа в запрос
PutObjectRequest.builder()
.sseCustomerAlgorithm("AES256") // или другой иной алгоритм, например: "AES128" / "GOST3412-2015" / "ChaCha20"
.sseCustomerKey(base64EncodedKey)
.sseCustomerKeyMD5(base64EncodedMd5CalculatedByKey)
// другие поля
.build()
Подпишите объект#
PutObjectRequest.builder()
.overrideConfiguration(builder -> {
builder.putHeader("x-amz-server-side-signature-suite", "key-store"); // или "key-store"
builder.putHeader("x-amz-server-side-signature-object-key", objectKey + ".sign");
})
// другие поля
.build()
Если требуется дополнительно шифрование, необходимо указать порядок наложения подписи
x-amz-server-side-signature-order.
PutObjectRequest.builder()
.overrideConfiguration(builder -> {
builder.putHeader("x-amz-server-side-signature-suite", "key-store"); // или "key-store"
builder.putHeader("x-amz-server-side-signature-object-key", objectKey + ".sign");
builder.putHeader("x-amz-server-side-signature-order", "before-encryption"); // или "after-encryption"
})
// другие поля
.build()
Рассчитайте digest (результат hash-функции) содержимого объекта (S3 ServerSideHash)#
PutObjectRequest.builder()
.overrideConfiguration(builder -> {
builder.putHeader("x-amz-server-side-hash-algorithm", "GOST3411-2012-256"); // или "GOST3411-2012-512"
})
// другие поля
.build()
Если рассчитать digest требуется одновременно с шифрованием, то также требуется указание порядка наложения ЭП:
PutObjectRequest.builder()
.overrideConfiguration(builder -> {
builder.putHeader("x-amz-server-side-hash-algorithm", "GOST3411-2012-256"); // или "GOST3411-2012-512"
builder.putHeader("x-amz-server-side-hash-order", "before-encryption"); // или "after-encryption"
})
// другие поля
.build()
Извлечение digest из ответа:
PutObjectResponse putObjectResponse = ...;
String base64EncodedDigest = putObjectResponse.sdkHttpResponse().headers().get("server-side-hash").get(0);
byte[] digest = Base64.getDecoder().decode(base64EncodedDigest);
Часто встречающиеся проблемы и пути их устранения#
проблемы с S3-совместимым хранилищем:
решение: Убедиться что для пользователя (access-key которого указан в конфигурации) разрешены операции чтения и записи в bucket, использующемся в интеграционном взаимодействии. Убедиться, что Bucket не переполнен и передаваемые файлы не занимают все свободное место в bucket.