# Configure storage for backups
You can configure storage for backups in the `backup.storages` subsection of the
Custom Resource, using the [deploy/cr.yaml :octicons-link-external-16:](https://github.com/percona/percona-server-mongodb-operator/blob/main/deploy/cr.yaml)
configuration file.
Before configuring the storage, you need to create a [Kubernetes Secret :octicons-link-external-16:](https://kubernetes.io/docs/concepts/configuration/secret/) object that contains the credentials needed to access your storage.
## Amazon S3 or S3-compatible storage
1. To store backups on the Amazon S3, you need to create a Secret with
the following values:
* the `metadata.name` key is the name which you will further use to refer
your Kubernetes Secret,
* the `data.AWS_ACCESS_KEY_ID` and `data.AWS_SECRET_ACCESS_KEY` keys are
base64-encoded credentials used to access the storage (obviously these
keys should contain proper values to make the access possible).
Create the Secrets file with these base64-encoded keys following the
[deploy/backup-s3.yaml :octicons-link-external-16:](https://github.com/percona/percona-server-mongodb-operator/blob/main/deploy/backup-s3.yaml)
example:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: my-cluster-name-backup-s3
type: Opaque
data:
AWS_ACCESS_KEY_ID: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ
AWS_SECRET_ACCESS_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ
```
!!! note
You can use the following command to get a base64-encoded string from a plain text one:
=== "in Linux"
```bash
echo -n 'plain-text-string' | base64 --wrap=0
```
=== "in macOS"
```bash
echo -n 'plain-text-string' | base64
```
Once the editing is over, create the Kubernetes Secret object as follows:
```bash
kubectl apply -f deploy/backup-s3.yaml
```
2. Put the data needed to access the S3-compatible cloud into the
`backup.storages` subsection of the Custom Resource.
* `storages..type` should be set to `s3` (substitute the part
with some arbitrary name you will later use to refer this storage when
making backups and restores).
* `storages..s3.credentialsSecret` key should be set to the name used
to refer your Kubernetes Secret (`my-cluster-name-backup-s3` in the last
example).
* `storages..s3.bucket` and `storages..s3.region` should contain
the S3 bucket and region. Also you can use `storages..s3.prefix`
option to specify the path (sub-folder) to the backups inside the S3
bucket. If prefix is not set, backups are stored in the root directory.
* if you use some S3-compatible storage instead of the original Amazon S3,
add the [endpointURL :octicons-link-external-16:](https://docs.min.io/docs/aws-cli-with-minio.html)
key in the `s3` subsection, which should point to the actual cloud used
for backups. This value and is specific to the cloud provider. For
example, using [Google Cloud :octicons-link-external-16:](https://cloud.google.com) involves the
[following :octicons-link-external-16:](https://storage.googleapis.com) endpointUrl:
```yaml
endpointUrl: https://storage.googleapis.com
```
The options within the `storages..s3` subsection are further explained
in the [Operator Custom Resource options](operator.md#operator-backup-section).
Here is an example
of the [deploy/cr.yaml :octicons-link-external-16:](https://github.com/percona/percona-server-mongodb-operator/blob/main/deploy/cr.yaml)
configuration file which configures Amazon S3 storage for backups:
```yaml
...
backup:
...
storages:
s3-us-west:
type: s3
s3:
bucket: S3-BACKUP-BUCKET-NAME-HERE
region: us-west-2
credentialsSecret: my-cluster-name-backup-s3
...
```
Finally, make sure that your storage has enough resources to store backups, which is
especially important in the case of large databases. It is clear that you need
enough free space on the storage. Beside that, S3 storage [upload limitats :octicons-link-external-16:](https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html)
include the maximum number 10000 parts, and backing up large data will result in
larger chunk sizes, which in turn may cause S3 server to run out of RAM, especially
within the default memory limits.
### Automating access to Amazon s3 based on IAM roles
Using AWS EC2 instances for backups makes it possible to automate access to AWS S3 buckets based on [Identity Access Management (IAM) roles :octicons-link-external-16:](https://kubernetes-on-aws.readthedocs.io/en/latest/user-guide/iam-roles.html) for Service Accounts with *no need to specify the S3 credentials explicitly*.
You can use either make and use the *IAM instance profile*, or configure *IAM roles for Service Accounts* (both ways heavily rely on AWS specifics, and need following the official Amazon documentation to be configured).
=== "Using IAM instance profile"
Following steps are needed to turn this feature on:
1. Create the [IAM instance profile :octicons-link-external-16:](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) and the permission policy within where you specify the access level that grants the access to S3 buckets.
2. Attach the IAM profile to an EC2 instance.
3. Configure an [S3 storage bucket in the Custom Resource](backups-storage.md#bucket) and verify the connection from the EC2 instance to it.
4. *Do not provide* `s3.credentialsSecret` for the storage in `deploy/cr.yaml`.
=== "Using IAM role for service account"
[IRSA :octicons-link-external-16:](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) is the native way for the cluster [running on Amazon Elastic Kubernetes Service (AWS EKS)](eks.md) to access the AWS API using permissions configured in AWS IAM roles.
Assuming that you have deployed the MongoDB Operator and the database cluster on [EKS, following our installation steps](eks.md), and your EKS cluster has [OpenID Connect issuer URL (OIDC) :octicons-link-external-16:](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html) enabled, the the high-level steps to configure it are the following:
1. Create an IAM role for your OIDC, and attach to the created role the policy that defines the access to an S3 bucket. See [official Amazon documentation :octicons-link-external-16:](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) for details.
2. Find out service accounts used for the Operator and for the database cluster. Service account for the Operator is `percona-server-mongodb-operator` (it is set by the `serviceAccountName` key in the `deploy/operator.yaml` or `deploy/bundle.yaml` manifest) The cluster's default account is `default` (it can be set with `serviceAccountName` Custom Resource option in the `replsets`, `sharding.configsvrReplSet`, and `sharding.mongos` subsections of the `deploy/cr.yaml` manifest).
3. Annotate both service accounts with the needed IAM roles. The commands should look as follows:
```bash
kubectl -n annotate serviceaccount default eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/my-role --overwrite
kubectl -n annotate serviceaccount percona-server-mongodb-operator eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/my-role --overwrite
```
Don't forget to substitute the `` and `` placeholders with the real namespaces, and use your IAM role instead of the `eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/my-role` example.
4. Configure an [S3 storage bucket in the Custom Resource](backups-storage.md#bucket) and verify the connection from the EC2 instance to it. *Do not provide* `s3.credentialsSecret` for the storage in `deploy/cr.yaml`.
!!! note
If IRSA-related credentials are defined, they have the priority over any IAM instance profile. S3 credentials in a secret, if present, override any IRSA/IAM instance profile related credentials and are used for authentication instead.
## Google Cloud storage
To use [Google Cloud Storage (GCS) :octicons-link-external-16:](https://cloud.google.com/storage) as an object store for backups, you need the following information:
* a GCS bucket name. Refer to the [GCS bucket naming guidelines :octicons-link-external-16:](https://cloud.google.com/storage/docs/buckets#naming) for bucket name requirements
* authentication keys for your service account in JSON format.
!!! note
You can still use the S3-compatible implementation of GCS with HMAC. Refer to the [Amazon S3 storage setup](#amazon-s3-or-s3-compatible-storage) section for steps.
However, we don't recommend their usage due to a [known issue in PBM :octicons-link-external-16:](https://docs.percona.com/percona-backup-mongodb/release-notes/2.11.0.html#known-limitations-for-using-hmac-keys-on-gcs) and encourage you to switch to using service accounts keys after the upgrade to the Operator version 1.21.0.
**Configuration steps**
{.power-number}
1. [Create a service account :octicons-link-external-16:](https://cloud.google.com/iam/docs/service-accounts-create#iam-service-accounts-create-console), if you don't have it already.
2. Add [JSON service keys for the service account :octicons-link-external-16:](https://cloud.google.com/iam/docs/creating-managing-service-account-keys). As the result a service account key file in JSON format with the private key and related information is automatically downloaded on your machine.
3. Encode your keys in base64 format. You need to encode the service account email and the private key. You can get these values from the service account key file you downloaded when you created the service account keys.
The following command shows how to encode a private key. Replace the placeholder with your private key and service account email:
```bash
echo -n "-----BEGIN PRIVATE KEY-----\nPRIVATE_KEY\n-----END PRIVATE KEY-----\n" | base64
```
4. Create the Kubernetes Secret configuration file and specify the encoded GCS credentials within:
```yaml title="gcp-cs-secret.yaml"
apiVersion: v1
kind: Secret
metadata:
name: gcp-cs-secret-key
type: Opaque
data:
GCS_CLIENT_EMAIL: base_64_encoded_email
GCS_PRIVATE_KEY: base_64_encoded_key
```
5. Create the Kubernetes Secrets object. Replace the `` placeholder with your value:
```bash
kubectl apply -f gcp-cs-secret.yaml -n
```
6. Configure the GCS storage in the `deploy/cr.yaml` Custom Resource. Specify the following information:
* Set `storages..type` to `gcs` (substitute the part
with some arbitrary name you will later use to refer this storage when
making backups and restores).
* Specify the bucket name for the `storages..gcs.bucket` option
* Specify the Secrets object name you created for the `storages..gcs.credentialsSecret` option
```yaml
backup:
storages:
gcp-cs:
type: gcs
gcs:
bucket: < GCS-BACKUP-BUCKET-NAME-HERE>
credentialsSecret: gcp-cs-secret
```
7. Apply the configuration:
```bash
kubectl apply -f deploy/cr.yaml -n
```
## Microsoft Azure Blob storage
1. To store backups on the Azure Blob storage, you need to create a
Secret with the following values:
* the `metadata.name` key is the name which you wll further use to refer
your Kubernetes Secret,
* the `data.AZURE_STORAGE_ACCOUNT_NAME` and `data.AZURE_STORAGE_ACCOUNT_KEY`
keys are base64-encoded credentials used to access the storage
(obviously these keys should contain proper values to make the access
possible).
Create the Secrets file with these base64-encoded keys following the
`deploy/backup-azure.yaml` example:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: my-cluster-azure-secret
type: Opaque
data:
AZURE_STORAGE_ACCOUNT_NAME: UkVQTEFDRS1XSVRILUFXUy1BQ0NFU1MtS0VZ
AZURE_STORAGE_ACCOUNT_KEY: UkVQTEFDRS1XSVRILUFXUy1TRUNSRVQtS0VZ
```
!!! note
You can use the following command to get a base64-encoded string from a plain text one:
=== "in Linux"
```bash
echo -n 'plain-text-string' | base64 --wrap=0
```
=== "in macOS"
```bash
echo -n 'plain-text-string' | base64
```
Once the editing is over, create the Kubernetes Secret object as follows:
```bash
kubectl apply -f deploy/backup-azure.yaml
```
2. Put the data needed to access the Azure Blob storage into the
`backup.storages` subsection of the Custom Resource.
* `storages..type` should be set to `azure` (substitute the part
with some arbitrary name you will later use to refer this storage when
making backups and restores).
* `storages..azure.credentialsSecret` key should be set to the name used
to refer your Kubernetes Secret (`my-cluster-azure-secret` in the last
example).
* `storages..azure.container` option should contain the name of the
Azure container. Also you can use `storages..azure.prefix`
option to specify the path (sub-folder) to the backups inside the
container. If prefix is not set, backups are stored in the root directory
of the container.
These and other options within the `storages..azure` subsection are
further described in the [Operator Custom Resource options](operator.md#operator-backup-section).
Here is an example
of the [deploy/cr.yaml :octicons-link-external-16:](https://github.com/percona/percona-server-mongodb-operator/blob/main/deploy/cr.yaml)
configuration file which configures Azure Blob storage for backups:
```yaml
...
backup:
...
storages:
azure-blob:
type: azure
azure:
container:
prefix: psmdb
credentialsSecret: my-cluster-azure-secret
...
```
## Remote file server
You can use the `filesystem` backup storage type to mount a *remote file server* to
a local directory as a *sidecar volume*, and make Percona Backup for MongoDB
use this directory as a storage for backups.
The approach is based on using common
[Network File System (NFS) protocol :octicons-link-external-16:](https://en.wikipedia.org/wiki/Network_File_System).
Particularly, this storage type is useful in network-restricted environments
without S3-compatible storage, or in cases with a non-standard storage service
that still supports NFS access.
1. Add the remote storage as a [sidecar volume](operator.md#replsetssidecarvolumesname)
in the `replset` section of the Custom Resource (and also in `configsvrReplSet`
in case of a sharded cluster). You will need to specify the server hostname
and some directory on it, as in the following example:
```yaml
replsets:
- name: rs0
...
sidecarVolumes:
- name: backup-nfs-vol
nfs:
server: "nfs-service.storage.svc.cluster.local"
path: "/psmdb-my-cluster-name-rs0"
...
```
The `backup-nfs-vol` name specified above will be used to refer this
sidecar volume in the backup section.
2. Now put the mount point (the local directory path to which the remote storage
will be mounted) and the name of your sidecar volume into the
`backup.volumeMounts` subsection of the Custom Resource:
```yaml
backup:
...
volumeMounts:
- mountPath: /mnt/nfs/
name: backup-nfs-vol
...
```
3. Finally, storage of the `filesystem` type needs to be configured in the
`backup.storages` subsection. It needs only the mount point:
```yaml
backup:
enabled: true
...
storages:
backup-nfs:
type: filesystem
filesystem:
path: /mnt/nfs/
```