forked from TrueCloudLab/restic
azure: add SAS authentication option
This commit is contained in:
parent
6cbeb4a9f9
commit
64a7ec5341
6 changed files with 55 additions and 4 deletions
14
changelog/unreleased/issue-2295
Normal file
14
changelog/unreleased/issue-2295
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Enhancement: Allow use of SAS token to authenticate to Azure
|
||||||
|
|
||||||
|
Previously restic only supported AccountKeys to authenticate to Azure
|
||||||
|
storage accounts, which necessitates giving a significant amount of
|
||||||
|
access.
|
||||||
|
|
||||||
|
We added support for Azure SAS tokens which are a more fine-grained
|
||||||
|
and time-limited manner of granting access. Set the `AZURE_ACCOUNT_NAME`
|
||||||
|
and `AZURE_ACCOUNT_SAS` environment variables to use a SAS token for
|
||||||
|
authentication. Note that if `AZURE_ACCOUNT_KEY` is set, it will take
|
||||||
|
preference.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/issues/2295
|
||||||
|
https://github.com/restic/restic/pull/3661
|
|
@ -596,6 +596,10 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro
|
||||||
cfg.AccountKey = options.NewSecretString(os.Getenv("AZURE_ACCOUNT_KEY"))
|
cfg.AccountKey = options.NewSecretString(os.Getenv("AZURE_ACCOUNT_KEY"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.AccountSAS.String() == "" {
|
||||||
|
cfg.AccountSAS = options.NewSecretString(os.Getenv("AZURE_ACCOUNT_SAS"))
|
||||||
|
}
|
||||||
|
|
||||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -499,6 +499,17 @@ account name and key as follows:
|
||||||
$ export AZURE_ACCOUNT_NAME=<ACCOUNT_NAME>
|
$ export AZURE_ACCOUNT_NAME=<ACCOUNT_NAME>
|
||||||
$ export AZURE_ACCOUNT_KEY=<SECRET_KEY>
|
$ export AZURE_ACCOUNT_KEY=<SECRET_KEY>
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ export AZURE_ACCOUNT_NAME=<ACCOUNT_NAME>
|
||||||
|
$ export AZURE_ACCOUNT_SAS=<SAS_TOKEN>
|
||||||
|
|
||||||
|
With the later form, ensure your ``SAS_TOKEN`` does not start with a leading
|
||||||
|
``?``. If the generated token starts with a leading ``?`` it is safe to just
|
||||||
|
delete the first character (the ``?``) before use.
|
||||||
|
|
||||||
Afterwards you can initialize a repository in a container called ``foo`` in the
|
Afterwards you can initialize a repository in a container called ``foo`` in the
|
||||||
root path like this:
|
root path like this:
|
||||||
|
|
||||||
|
|
|
@ -593,6 +593,7 @@ environment variables. The following lists these environment variables:
|
||||||
|
|
||||||
AZURE_ACCOUNT_NAME Account name for Azure
|
AZURE_ACCOUNT_NAME Account name for Azure
|
||||||
AZURE_ACCOUNT_KEY Account key for Azure
|
AZURE_ACCOUNT_KEY Account key for Azure
|
||||||
|
AZURE_ACCOUNT_SAS Shared access signatures (SAS) for Azure
|
||||||
|
|
||||||
GOOGLE_PROJECT_ID Project ID for Google Cloud Storage
|
GOOGLE_PROJECT_ID Project ID for Google Cloud Storage
|
||||||
GOOGLE_APPLICATION_CREDENTIALS Application Credentials for Google Cloud Storage (e.g. $HOME/.config/gs-secret-restic-key.json)
|
GOOGLE_APPLICATION_CREDENTIALS Application Credentials for Google Cloud Storage (e.g. $HOME/.config/gs-secret-restic-key.json)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -39,10 +40,29 @@ var _ restic.Backend = &Backend{}
|
||||||
|
|
||||||
func open(cfg Config, rt http.RoundTripper) (*Backend, error) {
|
func open(cfg Config, rt http.RoundTripper) (*Backend, error) {
|
||||||
debug.Log("open, config %#v", cfg)
|
debug.Log("open, config %#v", cfg)
|
||||||
|
var client storage.Client
|
||||||
client, err := storage.NewBasicClient(cfg.AccountName, cfg.AccountKey.Unwrap())
|
var err error
|
||||||
if err != nil {
|
if cfg.AccountKey.String() != "" {
|
||||||
return nil, errors.Wrap(err, "NewBasicClient")
|
// We have an account key value, find the BlobServiceClient
|
||||||
|
// from with a BasicClient
|
||||||
|
debug.Log(" - using account key")
|
||||||
|
client, err = storage.NewBasicClient(cfg.AccountName, cfg.AccountKey.Unwrap())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "NewBasicClient")
|
||||||
|
}
|
||||||
|
} else if cfg.AccountSAS.String() != "" {
|
||||||
|
// Get the client using the SAS Token as authentication, this
|
||||||
|
// is longer winded than above because the SDK wants a URL for the Account
|
||||||
|
// if your using a SAS token, and not just the account name
|
||||||
|
// we (as per the SDK ) assume the default Azure portal.
|
||||||
|
url := fmt.Sprintf("https://%s.blob.core.windows.net/", cfg.AccountName)
|
||||||
|
debug.Log(" - using sas token")
|
||||||
|
client, err = storage.NewAccountSASClientFromEndpointToken(url, cfg.AccountSAS.Unwrap())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "NewAccountSASClientFromEndpointToken")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("no azure authentication information found")
|
||||||
}
|
}
|
||||||
|
|
||||||
client.HTTPClient = &http.Client{Transport: rt}
|
client.HTTPClient = &http.Client{Transport: rt}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
// server.
|
// server.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
AccountName string
|
AccountName string
|
||||||
|
AccountSAS options.SecretString
|
||||||
AccountKey options.SecretString
|
AccountKey options.SecretString
|
||||||
Container string
|
Container string
|
||||||
Prefix string
|
Prefix string
|
||||||
|
|
Loading…
Reference in a new issue