From 5f4f997126464eee08bc65a62b5dbd4664562277 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Sun, 24 Sep 2017 10:10:56 -0700 Subject: [PATCH 1/2] gs: minor comment cleanups * Remove a reference to S3. * Config can only be used for GCS, not other "gcs compatibile servers". * Make comments complete sentences. --- internal/backend/gs/config.go | 4 ++-- internal/backend/gs/gs.go | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/backend/gs/config.go b/internal/backend/gs/config.go index cc1b7d805..eebd4fe23 100644 --- a/internal/backend/gs/config.go +++ b/internal/backend/gs/config.go @@ -8,8 +8,8 @@ import ( "github.com/restic/restic/internal/options" ) -// Config contains all configuration necessary to connect to an gcs compatible -// server. +// Config contains all configuration necessary to connect to a Google Cloud +// Storage bucket. type Config struct { ProjectID string JSONKeyPath string diff --git a/internal/backend/gs/gs.go b/internal/backend/gs/gs.go index 902726d1b..c70e82e9d 100644 --- a/internal/backend/gs/gs.go +++ b/internal/backend/gs/gs.go @@ -1,3 +1,4 @@ +// Package gs provides a restic backend for Google Cloud Storage. package gs import ( @@ -31,7 +32,7 @@ type Backend struct { backend.Layout } -// make sure that *Backend implements backend.Backend +// Ensure that *Backend implements restic.Backend. var _ restic.Backend = &Backend{} func getStorageService(jsonKeyPath string) (*storage.Service, error) { @@ -87,21 +88,20 @@ func open(cfg Config) (*Backend, error) { return be, nil } -// Open opens the gs backend at bucket and region. +// Open opens the gs backend at the specified bucket. func Open(cfg Config) (restic.Backend, error) { return open(cfg) } -// Create opens the S3 backend at bucket and region and creates the bucket if -// it does not exist yet. +// Create opens the gs backend at the specified bucket and creates the bucket +// if it does not exist yet. func Create(cfg Config) (restic.Backend, error) { be, err := open(cfg) - if err != nil { return nil, errors.Wrap(err, "open") } - // Create bucket if not exists + // Create bucket if it doesn't exist. if _, err := be.service.Buckets.Get(be.bucketName).Do(); err != nil { bucket := &storage.Bucket{ Name: be.bucketName, @@ -371,5 +371,5 @@ func (be *Backend) Delete(ctx context.Context) error { return be.Remove(ctx, restic.Handle{Type: restic.ConfigFile}) } -// Close does nothing +// Close does nothing. func (be *Backend) Close() error { return nil } From 3b2106ed30303350d3a73f37d0295f68f42a44b5 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Sun, 24 Sep 2017 11:25:57 -0700 Subject: [PATCH 2/2] gs: document required permissions In the manual, state which standard roles the service account must have to work correctly, as well as the specific permissions required, for creating even more specific custom roles. --- doc/manual.rst | 22 ++++++++++++++++++---- internal/backend/gs/gs.go | 13 ++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 3e205e6c1..6841deb21 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -405,11 +405,22 @@ established. Google Cloud Storage ~~~~~~~~~~~~~~~~~~~~ -Restic supports Google Cloud Storage as a backend. In order for this to work -you first need create a "service account" and download the JSON key file for -it. In addition, you need the Google Project ID that you can see in the Google +Restic supports Google Cloud Storage as a backend. + +Restic connects to Google Cloud Storage via a `service account`_. + +For normal restic operation, the service account must have the +``storage.objects.{create,delete,get,list}`` permissions for the bucket. These +are included in the "Storage Object Admin" role. For ``restic init``, the +service account must also have the ``storage.buckets.get`` and +``storage.buckets.create`` (if the bucket does not exist) permissions. These +are included in the "Storage Admin" role. + +`Create a service account key`_ and download the JSON credentials file. + +In addition, you need the Google Project ID that you can see in the Google Cloud Platform console at the "Storage/Settings" menu. Export the path to the -JSON credentials file and the project ID as follows: +JSON key file and the project ID as follows: .. code-block:: console @@ -432,6 +443,9 @@ The number of concurrent connections to the GCS service can be set with the `-o gs.connections=10`. By default, at most five parallel connections are established. +.. _service account: https://cloud.google.com/storage/docs/authentication#service_accounts +.. _Create a service account key: https://cloud.google.com/storage/docs/authentication#generating-a-private-key + Password prompt on Windows ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/internal/backend/gs/gs.go b/internal/backend/gs/gs.go index c70e82e9d..ea003d955 100644 --- a/internal/backend/gs/gs.go +++ b/internal/backend/gs/gs.go @@ -21,7 +21,13 @@ import ( storage "google.golang.org/api/storage/v1" ) -// Backend stores data on an gs endpoint. +// Backend stores data in a GCS bucket. +// +// The service account used to access the bucket must have these permissions: +// * storage.objects.create +// * storage.objects.delete +// * storage.objects.get +// * storage.objects.list type Backend struct { service *storage.Service projectID string @@ -95,6 +101,11 @@ func Open(cfg Config) (restic.Backend, error) { // Create opens the gs backend at the specified bucket and creates the bucket // if it does not exist yet. +// +// In addition to the permissions required by Backend, Create requires these +// permissions: +// * storage.buckets.get +// * storage.buckets.create (if the bucket doesn't exist) func Create(cfg Config) (restic.Backend, error) { be, err := open(cfg) if err != nil {