Repository: gardener/etcd-backup-restore

Issue:
Embedded etcd does not work when base snaphot has etcd auth enabled
<!-- Please ensure that you do not include company internal information. -->

**How to categorize this issue?**
<!--
Please select area, kind, and priority for this issue. This helps the community categorizing it.
Replace below TODOs or exchange the existing identifiers with those that fit best in your opinion.
If multiple identifiers make sense you can also state the commands multiple times, e.g.
  /area control-plane
  /area auto-scaling
  ...

"/area" identifiers:     audit-logging|auto-scaling|backup|certification|control-plane-migration|control-plane|cost|delivery|dev-productivity|disaster-recovery|documentation|high-availability|logging|metering|monitoring|networking|open-source|ops-productivity|os|performance|quality|robustness|scalability|security|storage|testing|usability|user-management
"/kind" identifiers:     api-change|bug|cleanup|discussion|enhancement|epic|impediment|poc|post-mortem|question|regression|task|technical-debt|test
-->
/area backup
/kind bug

**What happened**:

Any operation that requires starting an embedded etcd does not work when base snapshot has etcd auth enabled.

When restoring a backup with incremental snapshots, output is something like this:

```
$ go run main.go restore --storage-provider=Local --store-container=/path/to/backup
INFO[0000] Finding latest set of snapshot to recover from... 
INFO[0000] Restoring from base snapshot: Full-00000000-8391520845-1763683200  actor=restorer
INFO[0000] successfully fetched data of base snapshot in 0.553876178 seconds  actor=restorer
INFO[0001] Starting embedded etcd server...              actor=restorer
INFO[0002] Embedded server is ready to listen client at: 127.0.0.1:43351  actor=restorer
INFO[0002] Applying delta snapshots...                   actor=restorer
INFO[0002] Applying first delta snapshot Incr-8391520846-8391652657-1763684913  actor=restorer
INFO[0002] successfully fetched data of delta snapshot in 0.093521816 seconds  actor=restorer
FATA[0004] Failed to restore snapshot: failed to get etcd latest revision: etcdserver: user name is empty 
```

**What you expected to happen**:

Embedded etcd should handle etcd authentication properly.

**How to reproduce it (as minimally and precisely as possible)**:

- Enable etcd auth on an etcd cluster (`etcdctl auth enable`)
- Backup the etcd cluster using this project, make sure there are incremental snapshots too.
- Try to run any operation which requires starting the embedded etcd server.

**Anything else we need to know?**:

- We "fixed" this issue by manually disabling auth after starting the embedded etcd server:

  ```go
  e.Server.AuthStore().AuthDisable()
  ```

  It then needs to be re-enabled manually.


**Environment**:

- etcd-backup-restore version: v0.40.0



Discussion:
@ishan16696: Hi @Tomy2e ,
Thanks for reporting this issue.
I tried to reproduce this issue but discovered some interesting things for which I need some clarity.
I enabled the auth in etcd by creating a user: `root` with role `root`, then I started my etcd-backup-restore but then backup-restore itself failed to take the full snapshot as it failed the authentication.
```
WARN[0007] Taking scheduled full snapshot failed: failed to get etcd latest revision: etcdserver: user name is empty  actor=snapshotter
ERRO[0007] Failed to take substitute full snapshot: failed to get etcd latest revision: etcdserver: user name is empty  actor=backup-restore-server
```
After this I was able to take the snapshot using `etcdctl` command by passing the user as `root`.
```
etcdctl snapshot save ~/backup.db --user=root:root
```

And this explains why backup-restore failed to take full-snapshot of etcd which has auth enabled. Now, my question to you is how you didn't face this issue first before facing this restoration issue ?

> INFO[0000] Restoring from base snapshot: Full-00000000-8391520845-1763683200  actor=restorer

you have your full snapshot, as per my analysis you should have faced this issue when full snapshot was triggered by backup-restore but as you have the full snapshot it means you have enable auth in etcd later (once full snapshot was taken) please correct me if I'm wrong .@Tomy2e: Hi @ishan16696, thank you for looking at this issue.

We use mTLS auth between etcd clients and servers, as described [here](https://etcd.io/docs/v3.4/op-guide/authentication/#using-tls-common-name) (this also allows us to have a passwordless `root` user).

This is currently supported by the backup-restore tool with these flags:

```bash
etcdbrctl snapshot \
--cacert ca.pem \
--cert root.pem \
--key root-key.pem
# etc.
```

Although I have not tried it, it also seems to be possible to provide a user/password to the `snapshot` command using `--etcd-username` and `--etcd-password`.

Let me know if you need more help to reproduce.@ishan16696: ok, thanks ... I'm able to reproduce it and yes, restoration fails while applying delta snapshot.
I think I found the issue, the issue seems to be during restoration etcd client creation is not considering the username and password for etcd, hence the authentication failed by embedded etcd for etcd client while restoration.@ishan16696: /assign@Tomy2e: > the issue seems to be during restoration etcd client creation is not considering the username and password for etcd, hence the authentication failed by embedded etcd for etcd client while restoration.

That's right, the etcd client must provide credentials when auth is enabled.

Unfortunately, providing a username and password would not solve the problem completely because etcd allows passwordless users, in which case using mTLS is required to authenticate. This means adding a TLS config to the embedded server and all clients. To avoid this, I found it simpler to just manually disable auth after embedded server is started using `e.Server.AuthStore().AuthDisable()`, as mentioned in my first post (it just needs to be enabled again afterwards).@ishan16696: > I found it simpler to just manually disable auth after embedded server is started using e.Server.AuthStore().AuthDisable(), as mentioned in my first post (it just needs to be enabled again afterwards).

Initially, I was also thinking this method but the problem about this method is detection of whether to disable and enable the auth for etcd or not.
Etcd-backup-restore restoration process can run this `e.Server.AuthStore().AuthDisable()` to disable auth as this works for both kind of restoration (those etcd which has auth enabled --> disable auth and for those who doesn't has auth enabled -> no effect of auth disable) but how to enable the auth at the end of restoration as we don't enable it for both kind of restoration. I tried with getting the auth information with `e.Server.AuthInfoFromCtx(context.TODO())` but it's not giving me any details.
```
....
INFO[0007] AuthInfo: <nil>
....
```
But if you have fix then feel free to open a PR, please make sure it should work for both kind of restoration (those etcd which has auth enabled and for those who doesn't has auth enabled).
For making this work with username and password https://github.com/gardener/etcd-backup-restore/issues/950#issuecomment-3617615951 that I will take care.@ishan16696: The problem is even to disable the auth you need username and password (if not certificates), it means when backup-restore do the restoration from full snapshot automatically auth get enabled as full-snapshot was taken from etcd which was running with auth enabled then every etcd API call must be authorised else it get failed.
example:
```
$ etcdctl auth disable                                                                      
{"level":"warn","ts":"2025-12-08T14:28:45.246986+0530","logger":"etcd-client","caller":"v3@v3.5.9/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0x140003dea80/127.0.0.1:2379","attempt":0,"error":"rpc error: code = InvalidArgument desc = etcdserver: user name is empty"}
Error: etcdserver: user name is empty

$ etcdctl auth disable --user=root:root                                                     
Authentication Disabled
```@Tomy2e: I have opened PR #954 to fix this issue using the `e.Server.AuthStore().AuthDisable()` method. I still need to add tests to make sure everything works as expected.
I used `e.Server.AuthStore().IsAuthEnabled()` to check if authentication needs to be disabled/enabled during runtime.@ishan16696: > e.Server.AuthStore().IsAuthEnabled()

this call seems to be working, I tried with this `e.Server.AuthInfoFromCtx()` it wasn't working. Anyway thanks for fixing it. I will review the PR once you open it for review.

Solution patch:
diff --git a/pkg/compactor/compactor.go b/pkg/compactor/compactor.go
index 1bdffe79..6a4ccec4 100644
--- a/pkg/compactor/compactor.go
+++ b/pkg/compactor/compactor.go
@@ -91,10 +91,7 @@ func (cp *Compactor) Compact(ctx context.Context, opts *brtypes.CompactOptions)
 		}
 	}
 
-	defer func() {
-		embeddedEtcd.Server.Stop()
-		embeddedEtcd.Close()
-	}()
+	defer embeddedEtcd.Close()
 
 	ep := []string{embeddedEtcd.Clients[0].Addr().String()}
 
diff --git a/pkg/initializer/validator/datavalidator.go b/pkg/initializer/validator/datavalidator.go
index 9257039d..31db7f9b 100644
--- a/pkg/initializer/validator/datavalidator.go
+++ b/pkg/initializer/validator/datavalidator.go
@@ -371,10 +371,7 @@ func (d *DataValidator) checkFullRevisionConsistency(dataDir string, latestSnaps
 		d.Logger.Infof("unable to start embedded etcd: %v", err)
 		return DataDirectoryCorrupt, err
 	}
-	defer func() {
-		e.Server.Stop()
-		e.Close()
-	}()
+	defer e.Close()
 
 	clientFactory := etcdutil.NewClientFactory(nil, brtypes.EtcdConnectionConfig{
 		Endpoints:         []string{e.Clients[0].Addr().String()},
diff --git a/pkg/miscellaneous/miscellaneous.go b/pkg/miscellaneous/miscellaneous.go
index ec2e8ac8..a09e1c39 100644
--- a/pkg/miscellaneous/miscellaneous.go
+++ b/pkg/miscellaneous/miscellaneous.go
@@ -32,6 +32,7 @@ import (
 	"go.etcd.io/etcd/etcdserver/api/v3rpc/rpctypes"
 	"go.etcd.io/etcd/etcdserver/etcdserverpb"
 	"go.etcd.io/etcd/pkg/types"
+	"go.uber.org/zap"
 	appsv1 "k8s.io/api/apps/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/wait"
@@ -155,8 +156,32 @@ func getStructuredBackupList(snapList brtypes.SnapList) []backup {
 	return backups
 }
 
+// EmbeddedEtcd contains a running etcd server and its listeners.
+type EmbeddedEtcd struct {
+	*embed.Etcd
+
+	// authWasDisabled tracks if auth was disabled during startup and we need to
+	// enable it again before closing the server.
+	authWasDisabled bool
+}
+
+// Close closes the etcd embedded server. If auth was disabled during startup,
+// it will re-enable auth before closing the server.
+func (e *EmbeddedEtcd) Close() {
+	if e.authWasDisabled {
+		if err := e.Etcd.Server.AuthStore().AuthEnable(); err != nil {
+			e.Etcd.GetLogger().Error("failed to enable auth again", zap.Error(err))
+		}
+	}
+
+	e.Etcd.Server.Stop()
+	e.Etcd.Close()
+}
+
 // StartEmbeddedEtcd starts the embedded etcd server.
-func StartEmbeddedEtcd(logger *logrus.Entry, ro *brtypes.RestoreOptions) (*embed.Etcd, error) {
+// Etcd auth is automatically disabled if needed: clients do not need to provide any credentials when sending requests.
+// If auth was disabled, it's automatically enabled again when server is closed.
+func StartEmbeddedEtcd(logger *logrus.Entry, ro *brtypes.RestoreOptions) (*EmbeddedEtcd, error) {
 	cfg := embed.NewConfig()
 	cfg.Dir = filepath.Join(ro.Config.DataDir)
 	DefaultListenPeerURLs := "http://localhost:0"
@@ -202,7 +227,16 @@ func StartEmbeddedEtcd(logger *logrus.Entry, ro *brtypes.RestoreOptions) (*embed
 		e.Close()
 		return nil, fmt.Errorf("server took too long to start")
 	}
-	return e, nil
+
+	embeddedEtcd := &EmbeddedEtcd{Etcd: e}
+
+	if e.Server.AuthStore().IsAuthEnabled() {
+		// Disable auth and record this action so that we can enable it again later.
+		embeddedEtcd.authWasDisabled = true
+		e.Server.AuthStore().AuthDisable()
+	}
+
+	return embeddedEtcd, nil
 }
 
 // GetKubernetesClientSetOrError creates and returns a kubernetes clientset or an error if creation fails
diff --git a/pkg/snapshot/restorer/restorer.go b/pkg/snapshot/restorer/restorer.go
index c9f7e534..724eceb7 100644
--- a/pkg/snapshot/restorer/restorer.go
+++ b/pkg/snapshot/restorer/restorer.go
@@ -30,7 +30,6 @@ import (
 	"github.com/sirupsen/logrus"
 	"go.etcd.io/etcd/clientv3"
 	"go.etcd.io/etcd/clientv3/snapshot"
-	"go.etcd.io/etcd/embed"
 	"go.etcd.io/etcd/mvcc/mvccpb"
 	"go.uber.org/zap"
 )
@@ -68,7 +67,6 @@ func (r *Restorer) RestoreAndStopEtcd(ro brtypes.RestoreOptions, m member.Contro
 	embeddedEtcd, err := r.Restore(ro, m)
 	defer func() {
 		if embeddedEtcd != nil {
-			embeddedEtcd.Server.Stop()
 			embeddedEtcd.Close()
 		}
 	}()
@@ -76,7 +74,7 @@ func (r *Restorer) RestoreAndStopEtcd(ro brtypes.RestoreOptions, m member.Contro
 }
 
 // Restore restores the etcd data directory as per specified restore options but returns the ETCD server that it statrted.
-func (r *Restorer) Restore(ro brtypes.RestoreOptions, m member.Control) (*embed.Etcd, error) {
+func (r *Restorer) Restore(ro brtypes.RestoreOptions, m member.Control) (*miscellaneous.EmbeddedEtcd, error) {
 	r.logger.Infof("Creating temporary directory %s for persisting full and delta snapshots locally.", ro.Config.TempSnapshotsDir)
 	err := os.MkdirAll(ro.Config.TempSnapshotsDir, 0700)
 	if err != nil {



Test patch:
diff --git a/pkg/compactor/compactor_suite_test.go b/pkg/compactor/compactor_suite_test.go
index 6d236d20..6d75918e 100644
--- a/pkg/compactor/compactor_suite_test.go
+++ b/pkg/compactor/compactor_suite_test.go
@@ -71,7 +71,7 @@ var _ = SynchronizedBeforeSuite(func() []byte {
 	resp := &utils.EtcdDataPopulationResponse{}
 	wg := &sync.WaitGroup{}
 	wg.Add(1)
-	go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, resp)
+	go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, "", "", resp)
 
 	// Take snapshots (Full + Delta) of the ETCD database
 	deltaSnapshotPeriod := time.Second
@@ -80,7 +80,7 @@ var _ = SynchronizedBeforeSuite(func() []byte {
 	compressionConfig.Enabled = true
 	compressionConfig.CompressionPolicy = "gzip"
 	snapstoreConfig := brtypes.SnapstoreConfig{Container: testSnapshotDir, Provider: "Local"}
-	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), true, compressionConfig)
+	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, "", "", ctx.Done(), true, compressionConfig)
 	Expect(err).ShouldNot(HaveOccurred())
 
 	// Wait until the populator finishes with populating ETCD
diff --git a/pkg/compactor/compactor_test.go b/pkg/compactor/compactor_test.go
index 52ba2106..f96d185f 100644
--- a/pkg/compactor/compactor_test.go
+++ b/pkg/compactor/compactor_test.go
@@ -190,7 +190,7 @@ var _ = Describe("Running Compactor", func() {
 				err = restorer.RestoreAndStopEtcd(*restoreOpts, nil)
 
 				Expect(err).ShouldNot(HaveOccurred())
-				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, logger)
+				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, "", "", logger)
 				Expect(err).ShouldNot(HaveOccurred())
 			})
 		})
@@ -269,7 +269,7 @@ var _ = Describe("Running Compactor", func() {
 				err = restorer.RestoreAndStopEtcd(*restoreOpts, nil)
 
 				Expect(err).ShouldNot(HaveOccurred())
-				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, logger)
+				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, "", "", logger)
 				Expect(err).ShouldNot(HaveOccurred())
 			})
 		})
diff --git a/pkg/defragmentor/defrag_test.go b/pkg/defragmentor/defrag_test.go
index 10939c0c..a076c8fa 100644
--- a/pkg/defragmentor/defrag_test.go
+++ b/pkg/defragmentor/defrag_test.go
@@ -132,7 +132,7 @@ var _ = Describe("Defrag", func() {
 			resp := &utils.EtcdDataPopulationResponse{}
 			wg := &sync.WaitGroup{}
 			wg.Add(1)
-			go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, resp)
+			go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, "", "", resp)
 			Expect(resp.Err).ShouldNot(HaveOccurred())
 
 			// Wait unitil the populator finishes with populating ETCD
diff --git a/pkg/initializer/validator/datavalidator_test.go b/pkg/initializer/validator/datavalidator_test.go
index a5dfd671..f385a37a 100644
--- a/pkg/initializer/validator/datavalidator_test.go
+++ b/pkg/initializer/validator/datavalidator_test.go
@@ -230,7 +230,7 @@ var _ = Describe("Running Datavalidator", func() {
 			endpoints := []string{etcd.Clients[0].Addr().String()}
 			// populate etcd but with lesser data than previous populate call, so that the new db has a lower revision
 			resp := &utils.EtcdDataPopulationResponse{}
-			utils.PopulateEtcd(testCtx, logger, endpoints, 0, int(keyTo/2), resp)
+			utils.PopulateEtcd(testCtx, logger, endpoints, "", "", 0, int(keyTo/2), resp)
 			Expect(resp.Err).ShouldNot(HaveOccurred())
 			etcd.Close()
 
@@ -270,7 +270,7 @@ var _ = Describe("Running Datavalidator", func() {
 
 			resp := &utils.EtcdDataPopulationResponse{}
 			// populate the etcd with some more keys
-			utils.PopulateEtcd(testCtx, logger, endpoints, 0, int(keyTo/2), resp)
+			utils.PopulateEtcd(testCtx, logger, endpoints, "", "", 0, int(keyTo/2), resp)
 			Expect(resp.Err).ShouldNot(HaveOccurred())
 
 			//run the snapshotter
diff --git a/pkg/initializer/validator/validator_suite_test.go b/pkg/initializer/validator/validator_suite_test.go
index 74029806..84f56df5 100644
--- a/pkg/initializer/validator/validator_suite_test.go
+++ b/pkg/initializer/validator/validator_suite_test.go
@@ -69,7 +69,7 @@ var _ = SynchronizedBeforeSuite(func() []byte {
 	resp := &utils.EtcdDataPopulationResponse{}
 	wg := &sync.WaitGroup{}
 	wg.Add(1)
-	go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, resp)
+	go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, "", "", resp)
 
 	deltaSnapshotPeriod := 5 * time.Second
 	ctx := utils.ContextWithWaitGroupFollwedByGracePeriod(populatorCtx, wg, deltaSnapshotPeriod+2*time.Second)
diff --git a/pkg/snapshot/copier/copier_suite_test.go b/pkg/snapshot/copier/copier_suite_test.go
index 1ecdfe91..6ba6cf57 100644
--- a/pkg/snapshot/copier/copier_suite_test.go
+++ b/pkg/snapshot/copier/copier_suite_test.go
@@ -66,14 +66,14 @@ var _ = SynchronizedBeforeSuite(func() []byte {
 	resp := &utils.EtcdDataPopulationResponse{}
 	wg := &sync.WaitGroup{}
 	wg.Add(1)
-	go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, resp)
+	go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, "", "", resp)
 
 	deltaSnapshotPeriod := time.Second
 	ctx := utils.ContextWithWaitGroupFollwedByGracePeriod(populatorCtx, wg, deltaSnapshotPeriod+2*time.Second)
 
 	compressionConfig := compressor.NewCompressorConfig()
 	snapstoreConfig := brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), true, compressionConfig)
+	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, "", "", ctx.Done(), true, compressionConfig)
 	Expect(err).ShouldNot(HaveOccurred())
 
 	keyTo = resp.KeyTo
diff --git a/pkg/snapshot/restorer/restorer_suite_test.go b/pkg/snapshot/restorer/restorer_suite_test.go
index 91eb4187..200b4876 100644
--- a/pkg/snapshot/restorer/restorer_suite_test.go
+++ b/pkg/snapshot/restorer/restorer_suite_test.go
@@ -67,14 +67,14 @@ var _ = SynchronizedBeforeSuite(func() []byte {
 	resp := &utils.EtcdDataPopulationResponse{}
 	wg := &sync.WaitGroup{}
 	wg.Add(1)
-	go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, resp)
+	go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, "", "", resp)
 
 	deltaSnapshotPeriod := time.Second
 	ctx := utils.ContextWithWaitGroupFollwedByGracePeriod(populatorCtx, wg, deltaSnapshotPeriod+2*time.Second)
 
 	compressionConfig := compressor.NewCompressorConfig()
 	snapstoreConfig := brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), true, compressionConfig)
+	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, "", "", ctx.Done(), true, compressionConfig)
 	Expect(err).ShouldNot(HaveOccurred())
 
 	keyTo = resp.KeyTo
diff --git a/pkg/snapshot/restorer/restorer_test.go b/pkg/snapshot/restorer/restorer_test.go
index 5bcbe5d5..fa87f6d8 100644
--- a/pkg/snapshot/restorer/restorer_test.go
+++ b/pkg/snapshot/restorer/restorer_test.go
@@ -182,7 +182,7 @@ var _ = Describe("Running Restorer", func() {
 				err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 				Expect(err).ShouldNot(HaveOccurred())
 
-				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, logger)
+				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, "", "", logger)
 				Expect(err).ShouldNot(HaveOccurred())
 			})
 		})
@@ -194,7 +194,7 @@ var _ = Describe("Running Restorer", func() {
 				err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 				Expect(err).ShouldNot(HaveOccurred())
 
-				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, logger)
+				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, "", "", logger)
 				Expect(err).ShouldNot(HaveOccurred())
 			})
 		})
@@ -206,7 +206,7 @@ var _ = Describe("Running Restorer", func() {
 				err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 				Expect(err).ShouldNot(HaveOccurred())
 
-				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, logger)
+				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, "", "", logger)
 				Expect(err).ShouldNot(HaveOccurred())
 			})
 		})
@@ -242,7 +242,7 @@ var _ = Describe("Running Restorer", func() {
 	Describe("NEGATIVE:For Dynamic Loads and Negative Scenarios", func() {
 		var (
 			deltaSnapshotPeriod time.Duration
-			endpoints           []string
+			ep                  []string
 			restorationConfig   *brtypes.RestorationConfig
 		)
 
@@ -250,7 +250,7 @@ var _ = Describe("Running Restorer", func() {
 			deltaSnapshotPeriod = time.Second
 			etcd, err = utils.StartEmbeddedEtcd(testCtx, etcdDir, logger, utils.DefaultEtcdName, embeddedEtcdPortNo)
 			Expect(err).ShouldNot(HaveOccurred())
-			endpoints = []string{etcd.Clients[0].Addr().String()}
+			ep = []string{etcd.Clients[0].Addr().String()}
 
 			store, err = snapstore.GetSnapstore(&brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"})
 			Expect(err).ShouldNot(HaveOccurred())
@@ -287,13 +287,13 @@ var _ = Describe("Running Restorer", func() {
 			It("should restore from the delta snapshots ", func() {
 				wg.Add(1)
 				populatorCtx, cancelPopulator := context.WithTimeout(testCtx, 2)
-				go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, nil)
+				go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, ep, "", "", nil)
 				defer cancelPopulator()
 				logger.Infoln("Starting snapshotter with basesnapshot set to false")
 				ssrCtx := utils.ContextWithWaitGroupFollwedByGracePeriod(testCtx, wg, 2)
 				compressionConfig := compressor.NewCompressorConfig()
 				snapstoreConfig := brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ssrCtx.Done(), startWithFullSnapshot, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ssrCtx.Done(), startWithFullSnapshot, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				etcd.Server.Stop()
 				etcd.Close()
@@ -324,7 +324,7 @@ var _ = Describe("Running Restorer", func() {
 				err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 				Expect(err).ShouldNot(HaveOccurred())
 
-				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, logger)
+				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, "", "", logger)
 				Expect(err).ShouldNot(HaveOccurred())
 			})
 		})
@@ -335,12 +335,12 @@ var _ = Describe("Running Restorer", func() {
 				logger.Infoln("Starting snapshotter for no delta snapshots")
 				wg.Add(1)
 				populatorCtx, cancelPopulator := context.WithTimeout(testCtx, 2*time.Second)
-				go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, nil)
+				go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, ep, "", "", nil)
 				defer cancelPopulator()
 				ssrCtx := utils.ContextWithWaitGroupFollwedByGracePeriod(testCtx, wg, time.Second)
 				compressionConfig := compressor.NewCompressorConfig()
 				snapstoreConfig := brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ssrCtx.Done(), true, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ssrCtx.Done(), true, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				etcd.Server.Stop()
 				etcd.Close()
@@ -375,12 +375,12 @@ var _ = Describe("Running Restorer", func() {
 				logger.Infoln("Starting snapshotter for corrupted snapstore")
 				wg.Add(1)
 				populatorCtx, cancelPopulator := context.WithTimeout(testCtx, 2*time.Second)
-				go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, nil)
+				go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, ep, "", "", nil)
 				defer cancelPopulator()
 				ssrCtx := utils.ContextWithWaitGroupFollwedByGracePeriod(testCtx, wg, time.Second)
 				compressionConfig := compressor.NewCompressorConfig()
 				snapstoreConfig := brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ssrCtx.Done(), true, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ssrCtx.Done(), true, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				etcd.Close()
 
@@ -423,12 +423,12 @@ var _ = Describe("Running Restorer", func() {
 				logger.Infoln("Starting snapshotter for not cleaned etcd dir scenario")
 				wg.Add(1)
 				populatorCtx, cancelPopulator := context.WithTimeout(testCtx, 2*time.Second)
-				go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, endpoints, nil)
+				go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, ep, "", "", nil)
 				defer cancelPopulator()
 				ssrCtx := utils.ContextWithWaitGroupFollwedByGracePeriod(testCtx, wg, 2*time.Second)
 				compressionConfig := compressor.NewCompressorConfig()
 				snapstoreConfig := brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ssrCtx.Done(), true, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ssrCtx.Done(), true, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				etcd.Close()
 
@@ -463,13 +463,13 @@ var _ = Describe("Running Restorer", func() {
 				compressionConfig.Enabled = false
 				ctx, cancel := context.WithTimeout(testCtx, time.Duration(2*time.Second))
 				snapstoreConfig := brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), true, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ctx.Done(), true, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				cancel()
 
 				// populate the etcd with some more data
 				resp := &utils.EtcdDataPopulationResponse{}
-				utils.PopulateEtcd(testCtx, logger, endpoints, 0, keyTo, resp)
+				utils.PopulateEtcd(testCtx, logger, ep, "", "", 0, keyTo, resp)
 				Expect(resp.Err).ShouldNot(HaveOccurred())
 
 				// start the Snapshotter with compressionPolicy = "lzw" to take delta snapshot
@@ -478,13 +478,13 @@ var _ = Describe("Running Restorer", func() {
 				compressionConfig.CompressionPolicy = "lzw"
 				ctx, cancel = context.WithTimeout(testCtx, time.Duration(2*time.Second))
 				snapstoreConfig = brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), false, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ctx.Done(), false, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				cancel()
 
 				// populate the etcd with some data
 				resp = &utils.EtcdDataPopulationResponse{}
-				utils.PopulateEtcd(testCtx, logger, endpoints, 0, keyTo, resp)
+				utils.PopulateEtcd(testCtx, logger, ep, "", "", 0, keyTo, resp)
 				Expect(resp.Err).ShouldNot(HaveOccurred())
 
 				// start the Snapshotter with compressionPolicy = "gzip"(default) to take delta snapshot
@@ -492,13 +492,13 @@ var _ = Describe("Running Restorer", func() {
 				compressionConfig.Enabled = true
 				ctx, cancel = context.WithTimeout(testCtx, time.Duration(2*time.Second))
 				snapstoreConfig = brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), false, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ctx.Done(), false, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				cancel()
 
 				// populate the etcd with some data
 				resp = &utils.EtcdDataPopulationResponse{}
-				utils.PopulateEtcd(testCtx, logger, endpoints, 0, keyTo, resp)
+				utils.PopulateEtcd(testCtx, logger, ep, "", "", 0, keyTo, resp)
 				Expect(resp.Err).ShouldNot(HaveOccurred())
 
 				// start the Snapshotter with compressionPolicy = "zlib" to take delta snapshot
@@ -507,7 +507,7 @@ var _ = Describe("Running Restorer", func() {
 				compressionConfig.CompressionPolicy = "zlib"
 				ctx, cancel = context.WithTimeout(testCtx, time.Duration(2*time.Second))
 				snapstoreConfig = brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), false, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ctx.Done(), false, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				cancel()
 
@@ -531,7 +531,7 @@ var _ = Describe("Running Restorer", func() {
 
 				err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 				Expect(err).ShouldNot(HaveOccurred())
-				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, logger)
+				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, "", "", logger)
 				Expect(err).ShouldNot(HaveOccurred())
 			})
 		})
@@ -541,7 +541,7 @@ var _ = Describe("Running Restorer", func() {
 
 				// populate the etcd with some data
 				resp := &utils.EtcdDataPopulationResponse{}
-				utils.PopulateEtcd(testCtx, logger, endpoints, 0, keyTo, resp)
+				utils.PopulateEtcd(testCtx, logger, ep, "", "", 0, keyTo, resp)
 				Expect(resp.Err).ShouldNot(HaveOccurred())
 
 				// start the Snapshotter with compressionPolicy = "gzip"(default) to take full snapshot.
@@ -549,13 +549,13 @@ var _ = Describe("Running Restorer", func() {
 				compressionConfig.Enabled = true
 				ctx, cancel := context.WithTimeout(testCtx, time.Duration(2*time.Second))
 				snapstoreConfig := brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), true, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ctx.Done(), true, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				cancel()
 
 				// populate the etcd with some more data
 				resp = &utils.EtcdDataPopulationResponse{}
-				utils.PopulateEtcd(testCtx, logger, endpoints, 0, keyTo, resp)
+				utils.PopulateEtcd(testCtx, logger, ep, "", "", 0, keyTo, resp)
 				Expect(resp.Err).ShouldNot(HaveOccurred())
 
 				// start the Snapshotter with compressionPolicy = "lzw" to take delta snapshot.
@@ -564,13 +564,13 @@ var _ = Describe("Running Restorer", func() {
 				compressionConfig.CompressionPolicy = "lzw"
 				ctx, cancel = context.WithTimeout(testCtx, time.Duration(2*time.Second))
 				snapstoreConfig = brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), false, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ctx.Done(), false, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				cancel()
 
 				// populate the etcd with some data
 				resp = &utils.EtcdDataPopulationResponse{}
-				utils.PopulateEtcd(testCtx, logger, endpoints, 0, keyTo, resp)
+				utils.PopulateEtcd(testCtx, logger, ep, "", "", 0, keyTo, resp)
 				Expect(resp.Err).ShouldNot(HaveOccurred())
 
 				// start the Snapshotter with compressionPolicy = "zlib" to take delta snapshot.
@@ -579,20 +579,20 @@ var _ = Describe("Running Restorer", func() {
 				compressionConfig.CompressionPolicy = "zlib"
 				ctx, cancel = context.WithTimeout(testCtx, time.Duration(2*time.Second))
 				snapstoreConfig = brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), false, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ctx.Done(), false, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				cancel()
 
 				// populate the etcd with some more data
 				resp = &utils.EtcdDataPopulationResponse{}
-				utils.PopulateEtcd(testCtx, logger, endpoints, 0, keyTo, resp)
+				utils.PopulateEtcd(testCtx, logger, ep, "", "", 0, keyTo, resp)
 				Expect(resp.Err).ShouldNot(HaveOccurred())
 
 				// start the Snapshotter with compression not enabled to take delta snapshot.
 				compressionConfig = compressor.NewCompressorConfig()
 				ctx, cancel = context.WithTimeout(testCtx, time.Duration(2*time.Second))
 				snapstoreConfig = brtypes.SnapstoreConfig{Container: snapstoreDir, Provider: "Local"}
-				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), false, compressionConfig)
+				err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, ep, "", "", ctx.Done(), false, compressionConfig)
 				Expect(err).ShouldNot(HaveOccurred())
 				cancel()
 
@@ -616,7 +616,7 @@ var _ = Describe("Running Restorer", func() {
 
 				err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 				Expect(err).ShouldNot(HaveOccurred())
-				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, logger)
+				err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, keyTo, "", "", logger)
 				Expect(err).ShouldNot(HaveOccurred())
 			})
 		})
@@ -927,7 +927,7 @@ var _ = Describe("Running Restorer when both v1 and v2 directory structures are
 
 			err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 			Expect(err).ShouldNot(HaveOccurred())
-			err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, resp.KeyTo, logger)
+			err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, resp.KeyTo, "", "", logger)
 			Expect(err).ShouldNot(HaveOccurred())
 		})
 	})
@@ -960,7 +960,7 @@ var _ = Describe("Running Restorer when both v1 and v2 directory structures are
 
 			err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 			Expect(err).ShouldNot(HaveOccurred())
-			err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, resp.KeyTo, logger)
+			err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, resp.KeyTo, "", "", logger)
 			Expect(err).ShouldNot(HaveOccurred())
 		})
 	})
@@ -993,7 +993,7 @@ var _ = Describe("Running Restorer when both v1 and v2 directory structures are
 
 			err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 			Expect(err).ShouldNot(HaveOccurred())
-			err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, resp.KeyTo, logger)
+			err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, resp.KeyTo, "", "", logger)
 			Expect(err).ShouldNot(HaveOccurred())
 		})
 	})
@@ -1028,7 +1028,7 @@ var _ = Describe("Running Restorer when both v1 and v2 directory structures are
 
 			err = restorer.RestoreAndStopEtcd(restoreOpts, nil)
 			Expect(err).ShouldNot(HaveOccurred())
-			err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, resp.KeyTo, logger)
+			err = utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, resp.KeyTo, "", "", logger)
 			Expect(err).ShouldNot(HaveOccurred())
 		})
 	})
@@ -1067,6 +1067,129 @@ var _ = Describe("Running Restorer when both v1 and v2 directory structures are
 	})
 })
 
+var _ = Describe("Running Restorer when base snapshot has etcd auth enabled", func() {
+	var (
+		restorer            *Restorer
+		restorePeerURLs     []string
+		clusterUrlsMap      types.URLsMap
+		peerUrls            types.URLs
+		baseSnapshot        *brtypes.Snapshot
+		deltaSnapList       brtypes.SnapList
+		store               brtypes.SnapStore
+		deltaSnapshotPeriod time.Duration
+		ep                  []string
+		etcdDataDir         string
+		restoreTempDir      string
+		testDir             string
+		storeDir            string
+		restorationConfig   *brtypes.RestorationConfig
+	)
+	const (
+		restoreName             string = "default"
+		restoreClusterToken     string = "etcd-cluster"
+		restoreCluster          string = "default=http://localhost:2380"
+		skipHashCheck           bool   = false
+		maxFetchers             uint   = 6
+		maxCallSendMsgSize             = 2 * 1024 * 1024 //2Mib
+		maxRequestBytes                = 2 * 1024 * 1024 //2Mib
+		maxTxnOps                      = 2 * 1024
+		embeddedEtcdQuotaBytes  int64  = 8 * 1024 * 1024 * 1024
+		autoCompactionMode      string = "periodic"
+		autoCompactionRetention string = "0"
+		embeddedEtcdPortNo      string = "9089"
+		rootUsername                   = "root"
+		rootPssword                    = "toor" // Typo in variable variable name to avoid secret scanner detection.
+	)
+
+	var (
+		resp *utils.EtcdDataPopulationResponse
+	)
+
+	BeforeEach(func() {
+		deltaSnapshotPeriod = time.Second
+		testDir = filepath.Join(outputDir, "restore-test-auth")
+		etcdDataDir = filepath.Join(testDir, "default.etcd")
+		restoreTempDir = filepath.Join(testDir, "default.restore.tmp")
+		storeDir = filepath.Join(testDir, "snapshotter.bkp")
+
+		etcd, err = utils.StartEmbeddedEtcd(testCtx, etcdDataDir, logger, utils.DefaultEtcdName, embeddedEtcdPortNo)
+		Expect(err).ShouldNot(HaveOccurred())
+		defer func() {
+			etcd.Server.Stop()
+			etcd.Close()
+		}()
+		ep = []string{etcd.Clients[0].Addr().String()}
+
+		Expect(utils.CreateRootUserAndEnableAuth(testCtx, ep, rootUsername, rootPssword)).To(Succeed())
+
+		populatorCtx, cancelPopulator := context.WithTimeout(testCtx, 15*time.Second)
+		defer cancelPopulator()
+		resp = &utils.EtcdDataPopulationResponse{}
+		wg := &sync.WaitGroup{}
+		wg.Add(1)
+		go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, ep, rootUsername, rootPssword, resp)
+
+		ctx := utils.ContextWithWaitGroupFollwedByGracePeriod(populatorCtx, wg, deltaSnapshotPeriod+2*time.Second)
+
+		compressionConfig := compressor.NewCompressorConfig()
+		snapstoreConfig := brtypes.SnapstoreConfig{Container: storeDir, Provider: "Local"}
+		err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, rootUsername, rootPssword, ctx.Done(), true, compressionConfig)
+		Expect(err).ShouldNot(HaveOccurred())
+
+		restorePeerURLs = []string{"http://localhost:2380"}
+		clusterUrlsMap, err = types.NewURLsMap(restoreCluster)
+		Expect(err).ShouldNot(HaveOccurred())
+		peerUrls, err = types.NewURLs(restorePeerURLs)
+		Expect(err).ShouldNot(HaveOccurred())
+
+		store, err = snapstore.GetSnapstore(&brtypes.SnapstoreConfig{Container: storeDir, Provider: "Local"})
+		Expect(err).ShouldNot(HaveOccurred())
+
+		restorationConfig = &brtypes.RestorationConfig{
+			DataDir:                  etcdDataDir,
+			TempSnapshotsDir:         restoreTempDir,
+			InitialClusterToken:      restoreClusterToken,
+			InitialCluster:           restoreCluster,
+			Name:                     restoreName,
+			InitialAdvertisePeerURLs: restorePeerURLs,
+			SkipHashCheck:            skipHashCheck,
+			MaxFetchers:              maxFetchers,
+			MaxCallSendMsgSize:       maxCallSendMsgSize,
+			MaxRequestBytes:          maxRequestBytes,
+			MaxTxnOps:                maxTxnOps,
+			EmbeddedEtcdQuotaBytes:   embeddedEtcdQuotaBytes,
+			AutoCompactionMode:       autoCompactionMode,
+			AutoCompactionRetention:  autoCompactionRetention,
+		}
+	})
+
+	It("should restore etcd data directory", func() {
+		baseSnapshot, deltaSnapList, err = miscellaneous.GetLatestFullSnapshotAndDeltaSnapList(store)
+		Expect(err).ShouldNot(HaveOccurred())
+
+		restorer, err = NewRestorer(store, logger)
+		Expect(err).ShouldNot(HaveOccurred())
+
+		Expect(deltaSnapList.Len()).To(Not(BeZero()), "there must be at least one delta snapshot for this test")
+
+		restoreOpts := brtypes.RestoreOptions{
+			Config:        restorationConfig,
+			BaseSnapshot:  baseSnapshot,
+			DeltaSnapList: deltaSnapList,
+			ClusterURLs:   clusterUrlsMap,
+			PeerURLs:      peerUrls,
+		}
+
+		Expect(os.RemoveAll(etcdDataDir)).To(Succeed())
+		Expect(restorer.RestoreAndStopEtcd(restoreOpts, nil)).To(Succeed())
+		Expect(utils.CheckDataConsistency(testCtx, restoreOpts.Config.DataDir, resp.KeyTo, rootUsername, rootPssword, logger)).To(Succeed())
+	})
+
+	AfterEach(func() {
+		Expect(os.RemoveAll(testDir)).To(Succeed())
+	})
+})
+
 var _ = Describe("Unit testing individual functions for restorer package", func() {
 	Describe("testing ErrorArrayToError", func() {
 		var (
@@ -1130,35 +1253,35 @@ func takeValidSnaps(logger *logrus.Entry, container string, resp *utils.EtcdData
 	//Add data into etcd
 	start := 0
 	stop := start + 10
-	utils.PopulateEtcd(testCtx, logger, endpoints, start, stop, resp)
+	utils.PopulateEtcd(testCtx, logger, endpoints, "", "", start, stop, resp)
 	Expect(resp.Err).ShouldNot(HaveOccurred())
 
 	//Take a full snapshot.
 	compressionConfig := compressor.NewCompressorConfig()
 	ctx, cancel := context.WithTimeout(testCtx, time.Duration(2*time.Second))
-	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), true, compressionConfig)
+	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, "", "", ctx.Done(), true, compressionConfig)
 	Expect(err).ShouldNot(HaveOccurred())
 	cancel()
 
 	//Add data into etcd
 	start = stop
 	stop = stop + 10
-	utils.PopulateEtcd(testCtx, logger, endpoints, start, stop, resp)
+	utils.PopulateEtcd(testCtx, logger, endpoints, "", "", start, stop, resp)
 	Expect(resp.Err).ShouldNot(HaveOccurred())
 	//Take delta snapshot.
 	ctx, cancel = context.WithTimeout(testCtx, time.Duration(2*time.Second))
-	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), false, compressionConfig)
+	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, "", "", ctx.Done(), false, compressionConfig)
 	Expect(err).ShouldNot(HaveOccurred())
 	cancel()
 
 	//Add data to etcd
 	start = stop
 	stop = stop + 10
-	utils.PopulateEtcd(testCtx, logger, endpoints, start, stop, resp)
+	utils.PopulateEtcd(testCtx, logger, endpoints, "", "", start, stop, resp)
 	Expect(resp.Err).ShouldNot(HaveOccurred())
 	//Take delta snapshot.
 	ctx, cancel = context.WithTimeout(testCtx, time.Duration(2*time.Second))
-	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, ctx.Done(), false, compressionConfig)
+	err = utils.RunSnapshotter(logger, snapstoreConfig, deltaSnapshotPeriod, endpoints, "", "", ctx.Done(), false, compressionConfig)
 	Expect(err).ShouldNot(HaveOccurred())
 	cancel()
 
diff --git a/pkg/snapshot/snapshotter/snapshotter_test.go b/pkg/snapshot/snapshotter/snapshotter_test.go
index 5c5724d0..9ef6d870 100644
--- a/pkg/snapshot/snapshotter/snapshotter_test.go
+++ b/pkg/snapshot/snapshotter/snapshotter_test.go
@@ -279,7 +279,7 @@ var _ = Describe("Snapshotter", func() {
 							wg := &sync.WaitGroup{}
 							wg.Add(1)
 							// populating etcd so that snapshots will be taken
-							go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, etcdConnectionConfig.Endpoints, nil)
+							go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, etcdConnectionConfig.Endpoints, "", "", nil)
 							ssrCtx := utils.ContextWithWaitGroup(testCtx, wg)
 							err = ssr.Run(ssrCtx.Done(), false)
 							Expect(err).ShouldNot(HaveOccurred())
@@ -309,7 +309,7 @@ var _ = Describe("Snapshotter", func() {
 							wg := &sync.WaitGroup{}
 							wg.Add(1)
 							// populating etcd so that snapshots will be taken
-							go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, etcdConnectionConfig.Endpoints, nil)
+							go utils.PopulateEtcdWithWaitGroup(populatorCtx, wg, logger, etcdConnectionConfig.Endpoints, "", "", nil)
 
 							ssr, err = NewSnapshotter(logger, snapshotterConfig, store, etcdConnectionConfig, compressionConfig, healthConfig, snapstoreConfig)
 							Expect(err).ShouldNot(HaveOccurred())
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 04fef62c..559b4e44 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -127,7 +127,8 @@ type EtcdDataPopulationResponse struct {
 
 // PopulateEtcd sequentially puts key-value pairs into the embedded etcd, from key <keyFrom> (including) to <keyTo> (excluding). Every key divisible by 10 will be
 // be added and deleted immediately. So, for such key you will observer two events on etcd PUT and DELETE and key not being present in etcd at end.
-func PopulateEtcd(ctx context.Context, logger *logrus.Entry, endpoints []string, keyFrom, keyTo int, response *EtcdDataPopulationResponse) {
+// A valid username and password must be provided if etcd auth is enabled.
+func PopulateEtcd(ctx context.Context, logger *logrus.Entry, endpoints []string, username, password string, keyFrom, keyTo int, response *EtcdDataPopulationResponse) {
 	if response == nil {
 		response = &EtcdDataPopulationResponse{}
 	}
@@ -136,6 +137,8 @@ func PopulateEtcd(ctx context.Context, logger *logrus.Entry, endpoints []string,
 	cli, err := clientv3.New(clientv3.Config{
 		Endpoints:   endpoints,
 		DialTimeout: 10 * time.Second,
+		Username:    username,
+		Password:    password,
 	})
 	if err != nil {
 		response.Err = fmt.Errorf("unable to start etcd client: %v", err)
@@ -182,9 +185,39 @@ func PopulateEtcd(ctx context.Context, logger *logrus.Entry, endpoints []string,
 }
 
 // PopulateEtcdWithWaitGroup sequentially puts key-value pairs into the embedded etcd, until stopped via context. Use `wg.Wait()` to make sure that etcd population has stopped completely.
-func PopulateEtcdWithWaitGroup(ctx context.Context, wg *sync.WaitGroup, logger *logrus.Entry, endpoints []string, resp *EtcdDataPopulationResponse) {
+// A valid username and password must be provided if etcd auth is enabled.
+func PopulateEtcdWithWaitGroup(ctx context.Context, wg *sync.WaitGroup, logger *logrus.Entry, endpoints []string, username, password string, resp *EtcdDataPopulationResponse) {
 	defer wg.Done()
-	PopulateEtcd(ctx, logger, endpoints, 0, math.MaxInt64, resp)
+	PopulateEtcd(ctx, logger, endpoints, username, password, 0, math.MaxInt64, resp)
+}
+
+// CreateRootUserAndEnableAuth does the following on an existing etcd cluster that has auth disabled:
+//   - Create a new user using the provided name and password.
+//   - Grant "root" role to the created user.
+//   - Enable auth in etcd.
+func CreateRootUserAndEnableAuth(ctx context.Context, endpoints []string, username, password string) error {
+	cli, err := clientv3.New(clientv3.Config{
+		Endpoints:   endpoints,
+		DialTimeout: 10 * time.Second,
+	})
+	if err != nil {
+		return err
+	}
+	defer cli.Close()
+
+	if _, err := cli.Auth.UserAdd(ctx, username, password); err != nil {
+		return err
+	}
+
+	if _, err := cli.Auth.UserGrantRole(ctx, username, "root"); err != nil {
+		return err
+	}
+
+	if _, err := cli.Auth.AuthEnable(ctx); err != nil {
+		return err
+	}
+
+	return nil
 }
 
 // ContextWithWaitGroup returns a copy of parent with a new Done channel. The returned
@@ -219,7 +252,8 @@ func ContextWithWaitGroupFollwedByGracePeriod(parent context.Context, wg *sync.W
 }
 
 // RunSnapshotter creates a snapshotter object and runs it for a duration specified by 'snapshotterDurationSeconds'
-func RunSnapshotter(logger *logrus.Entry, snapstoreConfig brtypes.SnapstoreConfig, deltaSnapshotPeriod time.Duration, endpoints []string, stopCh <-chan struct{}, startWithFullSnapshot bool, compressionConfig *compressor.CompressionConfig) error {
+// A valid username and password must be provided if etcd auth is enabled.
+func RunSnapshotter(logger *logrus.Entry, snapstoreConfig brtypes.SnapstoreConfig, deltaSnapshotPeriod time.Duration, endpoints []string, username, password string, stopCh <-chan struct{}, startWithFullSnapshot bool, compressionConfig *compressor.CompressionConfig) error {
 	store, err := snapstore.GetSnapstore(&snapstoreConfig)
 	if err != nil {
 		return err
@@ -228,6 +262,8 @@ func RunSnapshotter(logger *logrus.Entry, snapstoreConfig brtypes.SnapstoreConfi
 	etcdConnectionConfig := brtypes.NewEtcdConnectionConfig()
 	etcdConnectionConfig.ConnectionTimeout.Duration = 10 * time.Second
 	etcdConnectionConfig.Endpoints = endpoints
+	etcdConnectionConfig.Username = username
+	etcdConnectionConfig.Password = password
 
 	snapshotterConfig := &brtypes.SnapshotterConfig{
 		FullSnapshotSchedule:     "0 0 1 1 *",
@@ -249,16 +285,32 @@ func RunSnapshotter(logger *logrus.Entry, snapstoreConfig brtypes.SnapstoreConfi
 }
 
 // CheckDataConsistency starts an embedded etcd and checks for correctness of the values stored in etcd against the keys 'keyFrom' through 'keyTo'
-func CheckDataConsistency(ctx context.Context, dir string, keyTo int, logger *logrus.Entry) error {
+// A valid username and password must be provided if etcd auth is enabled.
+func CheckDataConsistency(ctx context.Context, dir string, keyTo int, username, password string, logger *logrus.Entry) error {
 	etcd, err := StartEmbeddedEtcd(ctx, dir, logger, DefaultEtcdName, EmbeddedEtcdPortNo)
 	if err != nil {
 		return fmt.Errorf("unable to start embedded etcd server: %v", err)
 	}
 	defer etcd.Close()
+
+	// If auth is enabled then username and password must be provided.
+	// Otherwise, no username or password should be provided.
+	if etcd.Server.AuthStore().IsAuthEnabled() {
+		if username == "" || password == "" {
+			return fmt.Errorf("a username and password must be set as etcd auth found to be enabled")
+		}
+	} else {
+		if username != "" || password != "" {
+			return fmt.Errorf("a username or password should not be set as etcd auth found to be disabled")
+		}
+	}
+
 	endpoints := []string{etcd.Clients[0].Addr().String()}
 	cli, err := clientv3.New(clientv3.Config{
 		Endpoints:   endpoints,
 		DialTimeout: 10 * time.Second,
+		Username:    username,
+		Password:    password,
 	})
 	if err != nil {
 		return fmt.Errorf("unable to start etcd client: %v", err)