Skip to content

Commit

Permalink
Add an ability to set static Temp URL key (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
kayrus authored Apr 7, 2023
1 parent 7e796dc commit f127ead
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 25 deletions.
33 changes: 23 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Velero Plugin for Openstack
# Velero Plugin for OpenStack

Openstack Cinder and Swift plugin for [velero](https://github.com/vmware-tanzu/velero/) backups.
OpenStack Cinder and Swift plugin for [velero](https://github.com/vmware-tanzu/velero/) backups.

This plugin is [included as community supported plugin by Velero organization](https://velero.io/plugins/).

## Table of Contents

- [Velero Plugin for Openstack](#velero-plugin-for-openstack)
- [Velero Plugin for OpenStack](#velero-plugin-for-openstack)
- [Compatibility](#compatibility)
- [Openstack Authentication Configuration](#openstack-authentication-configuration)
- [OpenStack Authentication Configuration](#openstack-authentication-configuration)
- [Authentication using environment variables](#authentication-using-environment-variables)
- [Authentication using file](#authentication-using-file)
- [Installation](#installation)
Expand All @@ -32,7 +32,7 @@ Below is a matrix of plugin versions and Velero versions for which the compatibi
| v0.2.x | v1.4.x, v1.5.x |
| v0.1.x | v1.4.x, v1.5.x |

## Openstack Authentication Configuration
## OpenStack Authentication Configuration

The order of authentication methods is following:
1. Authentication using environment variables takes precedence (including [Application Credentials](https://docs.openstack.org/keystone/queens/user/application_credentials.html#using-application-credentials)). You **must not** set env. variable `OS_CLOUD` when you want to authenticate using env. variables because authenticator will try to look for `clouds.y(a)ml` file and use it.
Expand All @@ -46,7 +46,7 @@ For authentication using application credentials you need to first create them u

### Authentication using Environment Variables

Configure velero container with your Openstack authentication environment variables:
Configure velero container with your OpenStack authentication environment variables:

```bash
# Keystone v2.0
Expand Down Expand Up @@ -74,17 +74,21 @@ export OS_APPLICATION_CREDENTIAL_SECRET=<APP_CRED_SECRET>
export OS_VERIFY="false"
export TLS_SKIP_VERIFY="true"

# A custom hash function to use for Temp URL generation
export OS_SWIFT_TEMP_URL_DIGEST=sha256
# If you want to override Swift account ID
export OS_SWIFT_ACCOUNT_OVERRIDE=<NEW_PROJECT_ID>
# In case if you have non-standard reseller prefixes
export OS_SWIFT_RESELLER_PREFIXES=AUTH_,SERVICE_
# A valid Temp URL key must be specified, when overriding the Swift account ID
export OS_SWIFT_TEMP_URL_KEY=secret-key

# If you want to completely override Swift endpoint URL
# Has a higher priority over the OS_SWIFT_ACCOUNT_OVERRIDE
export OS_SWIFT_ENDPOINT_OVERRIDE=http://my-local/v1/swift
```

If your Openstack cloud has separated Swift service (SwiftStack or different), you can specify special environment variables for Swift to authenticate it and keep the standard ones for Cinder:
If your OpenStack cloud has separated Swift service (SwiftStack or different), you can specify special environment variables for Swift to authenticate it and keep the standard ones for Cinder:

```bash
# Swift with SwiftStack
Expand Down Expand Up @@ -146,7 +150,7 @@ clouds:
application_credential_secret: <APPLICATION_CREDENTIAL_SECRET>
```
These 2 options allow you also to authenticate against multiple Openstack Clouds at the same time. The way you can leverage this functionality is scenario where you want to store backups in 2 different locations. This scenario doesn't apply for Volume Snapshots as they always need to be created in the same cloud and region as where your PVCs are created!
These 2 options allow you also to authenticate against multiple OpenStack Clouds at the same time. The way you can leverage this functionality is scenario where you want to store backups in 2 different locations. This scenario doesn't apply for Volume Snapshots as they always need to be created in the same cloud and region as where your PVCs are created!
Example of BSLs:
```yaml
Expand Down Expand Up @@ -188,13 +192,22 @@ spec:
### Container Setup
Swift container must have [Temporary URL Key](https://docs.openstack.org/swift/latest/api/temporary_url_middleware.html) configured to make it possible to download Velero backups. In your swift project you can execute following command to configure it:
Swift container must have [Temporary URL Key](https://docs.openstack.org/swift/latest/api/temporary_url_middleware.html) configured to make it possible to download Velero backups. In your Swift project you can execute following command to configure it:
```bash
SWIFT_TMP_URL_KEY=$(dd if=/dev/urandom | tr -dc A-Za-z0-9 | head -c 40)
swift post -m "Temp-URL-Key:${SWIFT_TMP_URL_KEY}"
```

Or per container Temporary URL key:

```bash
SWIFT_TMP_URL_KEY=$(dd if=/dev/urandom | tr -dc A-Za-z0-9 | head -c 40)
swift post -m "Temp-URL-Key:${SWIFT_TMP_URL_KEY}" my-container
```

> **Note:** If the Swift account ID is overridden (for example, if the current authentication project scope does not correspond to the destination container project ID), you must set the corresponding valid `OS_SWIFT_TEMP_URL_KEY` environment variable.
### Install using Velero CLI

Initialize velero plugin:
Expand Down Expand Up @@ -307,7 +320,7 @@ Alternative Kubernetes native solution (GA since 1.20) for volume snapshots (not

Volume backups with Velero can also be done using [Restic](https://velero.io/docs/main/restic/). Please understand that this repository does not provide any functionality for restic and restic implementation is done purely in Velero code.

There is a common similarity that `restic` can use Openstack Swift as object storage for backups. Restic way of authentication and implementation is however very different from this repository and it means that some ways of authentication that work here will not work with restic. Please refer to [official restic documentation](https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html#openstack-swift) to understand how are you supposed to configure authentication variables with restic.
There is a common similarity that `restic` can use OpenStack Swift as object storage for backups. Restic way of authentication and implementation is however very different from this repository and it means that some ways of authentication that work here will not work with restic. Please refer to [official restic documentation](https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html#openstack-swift) to understand how are you supposed to configure authentication variables with restic.

Recommended way of using this plugin with restic is to use authentication with environment variables and only for 1 cloud and 1 BackupStorageLocation. In the BSL you need to configure `config.resticRepoPrefix: swift:<CONTAINER_NAME>:/<PATH>` - for example `config.resticRepoPrefix: swift:my-awesome-container:/restic`.

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/Lirt/velero-plugin-swift
go 1.19

require (
github.com/gophercloud/gophercloud v1.0.0
github.com/gophercloud/gophercloud v1.3.1-0.20230331133731-6e0b5eac8554
github.com/gophercloud/utils v0.0.0-20220927104426-4113af8d2663
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gophercloud/gophercloud v0.20.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
github.com/gophercloud/gophercloud v1.0.0 h1:9nTGx0jizmHxDobe4mck89FyQHVyA3CaXLIUSGJjP9k=
github.com/gophercloud/gophercloud v1.0.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c=
github.com/gophercloud/gophercloud v1.3.1-0.20230331133731-6e0b5eac8554 h1:NITuyeCL/cDy/CSR38VaiY3sWBKJPGtt2yBWjPes4cU=
github.com/gophercloud/gophercloud v1.3.1-0.20230331133731-6e0b5eac8554/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/gophercloud/utils v0.0.0-20220927104426-4113af8d2663 h1:cHUPA6mgL0RGwopSxYRil6v8mK4ab6yefs1PJRXPXUE=
github.com/gophercloud/utils v0.0.0-20220927104426-4113af8d2663/go.mod h1:qOGlfG6OIJ193/c3Xt/XjOfHataNZdQcVgiu93LxBUM=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
Expand Down Expand Up @@ -338,9 +338,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down
4 changes: 2 additions & 2 deletions src/cinder/block_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ func (b *BlockStore) Init(config map[string]string) error {
b.log.Infof("BlockStore.Init called", config)
b.config = config

// Authenticate to Openstack
// Authenticate to OpenStack
err := utils.Authenticate(&b.provider, "cinder", config, b.log)
if err != nil {
return fmt.Errorf("failed to authenticate against openstack: %v", err)
return fmt.Errorf("failed to authenticate against OpenStack: %v", err)
}

// If we haven't set client before or we use multiple clouds - get new client
Expand Down
28 changes: 22 additions & 6 deletions src/swift/object_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import (

// ObjectStore is swift type that holds client and log
type ObjectStore struct {
client *gophercloud.ServiceClient
provider *gophercloud.ProviderClient
log logrus.FieldLogger
client *gophercloud.ServiceClient
provider *gophercloud.ProviderClient
log logrus.FieldLogger
tempURLKey string
tempURLDigest string
}

// NewObjectStore instantiates a Swift ObjectStore.
Expand All @@ -34,7 +36,7 @@ func (o *ObjectStore) Init(config map[string]string) error {

err := utils.Authenticate(&o.provider, "swift", config, o.log)
if err != nil {
return fmt.Errorf("failed to authenticate against Openstack: %v", err)
return fmt.Errorf("failed to authenticate against OpenStack: %v", err)
}

// If we haven't set client before or we use multiple clouds - get new client
Expand Down Expand Up @@ -83,6 +85,18 @@ func (o *ObjectStore) Init(config map[string]string) error {
o.log.Infof("Successfully overrode service client endpoint: %v", o.client.Endpoint)
}

// override the Temp URL hash function
o.tempURLDigest = utils.GetEnv("OS_SWIFT_TEMP_URL_DIGEST", "")
if o.tempURLDigest != "" {
o.log.Infof("Successfully overrode Temp URL digest to %s", o.tempURLDigest)
}

// override the Temp URL key to generate a URL signature
o.tempURLKey = utils.GetEnv("OS_SWIFT_TEMP_URL_KEY", "")
if o.tempURLKey != "" {
o.log.Infof("Successfully overrode Temp URL key")
}

return nil
}

Expand Down Expand Up @@ -216,8 +230,10 @@ func (o *ObjectStore) CreateSignedURL(container, object string, ttl time.Duratio
log.Infof("CreateSignedURL")

url, err := objects.CreateTempURL(o.client, container, object, objects.CreateTempURLOpts{
Method: http.MethodGet,
TTL: int(ttl.Seconds()),
Method: http.MethodGet,
TTL: int(ttl.Seconds()),
TempURLKey: o.tempURLKey,
Digest: o.tempURLDigest,
})
if err != nil {
return "", fmt.Errorf("failed to create temporary URL for %q object in %q container: %v", object, container, err)
Expand Down
4 changes: 2 additions & 2 deletions src/utils/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/sirupsen/logrus"
)

// Authenticate to Openstack and write client result to **pc
// Authenticate to OpenStack and write client result to **pc
func Authenticate(pc **gophercloud.ProviderClient, service string, config map[string]string, log logrus.FieldLogger) error {
var err error
var clientOpts clientconfig.ClientOpts
Expand Down Expand Up @@ -54,7 +54,7 @@ func Authenticate(pc **gophercloud.ProviderClient, service string, config map[st
AllowReauth: true,
}
} else {
log.Infof("Trying to authenticate against Openstack using environment variables (including application credentials) or using files ~/.config/openstack/clouds.yaml, /etc/openstack/clouds.yaml and ./clouds.yaml")
log.Infof("Trying to authenticate against OpenStack using environment variables (including application credentials) or using files ~/.config/openstack/clouds.yaml, /etc/openstack/clouds.yaml and ./clouds.yaml")
clientOpts.AuthInfo = &clientconfig.AuthInfo{
AllowReauth: true,
}
Expand Down

0 comments on commit f127ead

Please sign in to comment.