diff --git a/pkg/bootstrap/cloudinit/cloud-init.go b/pkg/bootstrap/cloudinit/cloud-init.go
index c8aef2e5b..77da0a6f3 100644
--- a/pkg/bootstrap/cloudinit/cloud-init.go
+++ b/pkg/bootstrap/cloudinit/cloud-init.go
@@ -74,7 +74,7 @@ func getNetworkData(docBundle document.Bundle) ([]byte, error) {
 	}
 
 	// try and find these documents in our bundle
-	selector, err = document.NewEphemeralNetworkDataSelector(bmhDoc)
+	selector, err = document.NewNetworkDataSelector(bmhDoc)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/document/bundle.go b/pkg/document/bundle.go
index 80326ad2b..7ecaa908b 100644
--- a/pkg/document/bundle.go
+++ b/pkg/document/bundle.go
@@ -47,6 +47,7 @@ type Bundle interface {
 	SetFileSystem(FileSystem) error
 	GetFileSystem() FileSystem
 	Select(selector Selector) ([]Document, error)
+	SelectOne(selector Selector) (Document, error)
 	SelectBundle(selector Selector) (Bundle, error)
 	SelectByFieldValue(string, func(interface{}) bool) (Bundle, error)
 	GetByGvk(string, string, string) ([]Document, error)
@@ -220,6 +221,29 @@ func (b *BundleFactory) Select(selector Selector) ([]Document, error) {
 	return docSet, err
 }
 
+// SelectOne serves the common use case where you expect one match
+// and only one match to your selector -- in other words, you want to
+// error if you didn't find any documents, and error if you found
+// more than one.  This reduces code repetition that would otherwise
+// be scattered around that evaluates the length of the doc set returned
+// for this common case
+func (b *BundleFactory) SelectOne(selector Selector) (Document, error) {
+	docSet, err := b.Select(selector)
+	if err != nil {
+		return nil, err
+	}
+
+	// evaluate docSet for at least one document, and no more than
+	// one document and raise errors as appropriate
+	switch numDocsFound := len(docSet); {
+	case numDocsFound == 0:
+		return nil, ErrDocNotFound{Selector: selector}
+	case numDocsFound > 1:
+		return nil, ErrMultipleDocsFound{Selector: selector}
+	}
+	return docSet[0], nil
+}
+
 // SelectBundle offers an interface to pass a Selector, built on top of kustomize Selector
 // to the bundle returning a new Bundle that matches the criteria.  This is useful
 // where you want to actually prune the underlying bundle you are working with
diff --git a/pkg/document/dochelper_baremetalhost.go b/pkg/document/dochelper_baremetalhost.go
new file mode 100644
index 000000000..95a6caeb4
--- /dev/null
+++ b/pkg/document/dochelper_baremetalhost.go
@@ -0,0 +1,60 @@
+package document
+
+// GetBMHNetworkData retrieves the associated network data string
+// for the bmh document supplied from the bundle supplied
+func GetBMHNetworkData(bmh Document, bundle Bundle) (string, error) {
+	// try and find these documents in our bundle
+	selector, err := NewNetworkDataSelector(bmh)
+	if err != nil {
+		return "", err
+	}
+	doc, err := bundle.SelectOne(selector)
+
+	if err != nil {
+		return "", err
+	}
+
+	networkData, err := GetSecretDataKey(doc, "networkData")
+	if err != nil {
+		return "", err
+	}
+	return networkData, nil
+}
+
+// GetBMHBMCAddress returns the bmc address for a particular the document supplied
+func GetBMHBMCAddress(bmh Document) (string, error) {
+	bmcAddress, err := bmh.GetString("spec.bmc.address")
+	if err != nil {
+		return "", err
+	}
+	return bmcAddress, nil
+}
+
+// GetBMHBMCCredentials returns the BMC credentials for the bmh document supplied from
+// the supplied bundle
+func GetBMHBMCCredentials(bmh Document, bundle Bundle) (username string, password string, err error) {
+	// extract the secret document name
+	bmcCredentialsName, err := bmh.GetString("spec.bmc.credentialsName")
+	if err != nil {
+		return "", "", err
+	}
+
+	// find the secret within the bundle supplied
+	selector := NewBMCCredentialsSelector(bmcCredentialsName)
+	doc, err := bundle.SelectOne(selector)
+	if err != nil {
+		return "", "", err
+	}
+
+	username, err = GetSecretDataKey(doc, "username")
+	if err != nil {
+		return "", "", err
+	}
+	password, err = GetSecretDataKey(doc, "password")
+	if err != nil {
+		return "", "", err
+	}
+
+	// extract the username and password from them
+	return username, password, nil
+}
diff --git a/pkg/document/dochelper_test.go b/pkg/document/dochelper_test.go
new file mode 100644
index 000000000..dde62ef9f
--- /dev/null
+++ b/pkg/document/dochelper_test.go
@@ -0,0 +1,55 @@
+package document_test
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"opendev.org/airship/airshipctl/pkg/document"
+	"opendev.org/airship/airshipctl/testutil"
+)
+
+func TestDocHelpers(t *testing.T) {
+	require := require.New(t)
+	assert := assert.New(t)
+
+	fSys := testutil.SetupTestFs(t, "testdata/dochelper")
+	bundle, err := document.NewBundle(fSys, "/", "/")
+	require.NoError(err, "Building Bundle Failed")
+	require.NotNil(bundle)
+
+	t.Run("GetBMHNetworkData", func(t *testing.T) {
+		// retrieve our single bmh in the dataset
+		selector := document.NewSelector().ByKind("BareMetalHost")
+		doc, err := bundle.SelectOne(selector)
+		require.NoError(err)
+
+		networkData, err := document.GetBMHNetworkData(doc, bundle)
+		require.NoError(err, "Unexpected error trying to GetBMHNetworkData")
+		assert.Equal(networkData, "some network data")
+	})
+
+	t.Run("GetBMHBMCAddress", func(t *testing.T) {
+		// retrieve our single bmh in the dataset
+		selector := document.NewSelector().ByKind("BareMetalHost")
+		doc, err := bundle.SelectOne(selector)
+		require.NoError(err)
+
+		bmcAddress, err := document.GetBMHBMCAddress(doc)
+		require.NoError(err, "Unexpected error trying to GetBMHBMCAddress")
+		assert.Equal(bmcAddress, "redfish+https://192.168.111.1/v1/Redfish/Foo/Bar")
+	})
+
+	t.Run("GetBMHBMCCredentials", func(t *testing.T) {
+		// retrieve our single bmh in the dataset
+		selector := document.NewSelector().ByKind("BareMetalHost")
+		doc, err := bundle.SelectOne(selector)
+		require.NoError(err)
+
+		bmcUsername, bmcPassword, err := document.GetBMHBMCCredentials(doc, bundle)
+		require.NoError(err, "Unexpected error trying to GetBMHBMCCredentials")
+		assert.Equal(bmcUsername, "username")
+		assert.Equal(bmcPassword, "password")
+	})
+}
diff --git a/pkg/document/dochelper_utils.go b/pkg/document/dochelper_utils.go
new file mode 100644
index 000000000..76d4750a4
--- /dev/null
+++ b/pkg/document/dochelper_utils.go
@@ -0,0 +1,44 @@
+package document
+
+import (
+	b64 "encoding/base64"
+)
+
+// GetSecretDataKey understands how to retrieve a specific top level key from a secret
+// that may have the data stored under a data or stringData field in which
+// case the key may be base64 encoded or it may be plain text
+//
+// it is meant to be used by other high level dochelpers
+func GetSecretDataKey(cfg Document, key string) (string, error) {
+	var needsBase64Decode = true
+	var docName = cfg.GetName()
+
+	// this purposely doesn't handle binaryData as that isn't
+	// something we could support anyways
+	data, err := cfg.GetStringMap("stringData")
+	if err == nil {
+		needsBase64Decode = false
+	} else {
+		data, err = cfg.GetStringMap("data")
+		if err != nil {
+			return "", ErrDocumentMalformed{
+				DocName: docName,
+				Message: "The secret document lacks a data or stringData top level field",
+			}
+		}
+	}
+
+	res, ok := data[key]
+	if !ok {
+		return "", ErrDocumentDataKeyNotFound{DocName: docName, Key: key}
+	}
+
+	if needsBase64Decode {
+		byteSlice, err := b64.StdEncoding.DecodeString(res)
+		if err != nil {
+			return "", err
+		}
+		return string(byteSlice), nil
+	}
+	return res, nil
+}
diff --git a/pkg/document/errors.go b/pkg/document/errors.go
index 769c7f208..84ca11334 100644
--- a/pkg/document/errors.go
+++ b/pkg/document/errors.go
@@ -9,6 +9,19 @@ type ErrDocNotFound struct {
 	Selector Selector
 }
 
+// ErrDocumentDataKeyNotFound returned if desired key within a document not found
+type ErrDocumentDataKeyNotFound struct {
+	DocName string
+	Key     string
+}
+
+// ErrDocumentMalformed returned if the document is structurally malformed
+// (e.g. missing required low level keys)
+type ErrDocumentMalformed struct {
+	DocName string
+	Message string
+}
+
 // ErrMultipleDocsFound returned if desired document not found
 type ErrMultipleDocsFound struct {
 	Selector Selector
@@ -18,6 +31,14 @@ func (e ErrDocNotFound) Error() string {
 	return fmt.Sprintf("Document filtered by selector %q found no documents", e.Selector)
 }
 
+func (e ErrDocumentDataKeyNotFound) Error() string {
+	return fmt.Sprintf("Document %q cannot retrieve data key %q", e.DocName, e.Key)
+}
+
+func (e ErrDocumentMalformed) Error() string {
+	return fmt.Sprintf("Document %q is malformed: %q", e.DocName, e.Message)
+}
+
 func (e ErrMultipleDocsFound) Error() string {
 	return fmt.Sprintf("Document filtered by selector %q found more than one document", e.Selector)
 }
diff --git a/pkg/document/selectors.go b/pkg/document/selectors.go
index 9dfd0595e..e4367c49c 100644
--- a/pkg/document/selectors.go
+++ b/pkg/document/selectors.go
@@ -64,7 +64,7 @@ func (s Selector) ByAnnotation(annotationSelector string) Selector {
 	return s
 }
 
-// EphemeralCloudDataSelector returns selector to get BaremetalHost for ephemeral node
+// NewEphemeralCloudDataSelector returns selector to get BaremetalHost for ephemeral node
 func NewEphemeralCloudDataSelector() Selector {
 	return NewSelector().ByKind(SecretKind).ByLabel(EphemeralUserDataSelector)
 }
@@ -74,11 +74,16 @@ func NewEphemeralBMHSelector() Selector {
 	return NewSelector().ByKind(BareMetalHostKind).ByLabel(EphemeralHostSelector)
 }
 
-// NewEphemeralNetworkDataSelector returns selector that can be used to get secret with
+// NewBMCCredentialsSelector returns selector to get BaremetalHost BMC credentials
+func NewBMCCredentialsSelector(name string) Selector {
+	return NewSelector().ByKind(SecretKind).ByName(name)
+}
+
+// NewNetworkDataSelector returns selector that can be used to get secret with
 // network data bmhDoc argument is a document interface, that should hold fields
 // spec.networkData.name and spec.networkData.namespace where to find the secret,
 // if either of these fields are not defined in Document error will be returned
-func NewEphemeralNetworkDataSelector(bmhDoc Document) (Selector, error) {
+func NewNetworkDataSelector(bmhDoc Document) (Selector, error) {
 	selector := NewSelector()
 	// extract the network data document pointer from the bmh document
 	netConfDocName, err := bmhDoc.GetString("spec.networkData.name")
diff --git a/pkg/document/selectors_test.go b/pkg/document/selectors_test.go
index fc038d58b..949221f94 100644
--- a/pkg/document/selectors_test.go
+++ b/pkg/document/selectors_test.go
@@ -24,7 +24,7 @@ func TestSelectorsPositive(t *testing.T) {
 		require.NoError(t, err)
 		assert.Len(t, docs, 1)
 		bmhDoc := docs[0]
-		selector, err := document.NewEphemeralNetworkDataSelector(bmhDoc)
+		selector, err := document.NewNetworkDataSelector(bmhDoc)
 		require.NoError(t, err)
 		assert.Equal(t, "validName", selector.Name)
 	})
@@ -42,12 +42,12 @@ func TestSelectorsNegative(t *testing.T) {
 	// test coverage
 	bundle := testutil.NewTestBundle(t, "testdata/selectors/invalid")
 
-	t.Run("TestNewEphemeralNetworkDataSelectorErr", func(t *testing.T) {
+	t.Run("TestNewNetworkDataSelectorErr", func(t *testing.T) {
 		docs, err := bundle.Select(document.NewEphemeralBMHSelector())
 		require.NoError(t, err)
 		assert.Len(t, docs, 2)
 		bmhDoc := docs[0]
-		_, err = document.NewEphemeralNetworkDataSelector(bmhDoc)
+		_, err = document.NewNetworkDataSelector(bmhDoc)
 		assert.Error(t, err)
 	})
 
@@ -56,7 +56,7 @@ func TestSelectorsNegative(t *testing.T) {
 		require.NoError(t, err)
 		assert.Len(t, docs, 2)
 		bmhDoc := docs[1]
-		_, err = document.NewEphemeralNetworkDataSelector(bmhDoc)
+		_, err = document.NewNetworkDataSelector(bmhDoc)
 		assert.Error(t, err)
 	})
 }
@@ -67,7 +67,7 @@ func TestSelectorsSkip(t *testing.T) {
 	// test coverage
 	bundle := testutil.NewTestBundle(t, "testdata/selectors/exclude-from-k8s")
 
-	t.Run("TestNewEphemeralNetworkDataSelectorErr", func(t *testing.T) {
+	t.Run("TestNewNetworkDataSelectorErr", func(t *testing.T) {
 		selector := document.NewDeployToK8sSelector()
 		docs, err := bundle.Select(selector)
 		require.NoError(t, err)
diff --git a/pkg/document/testdata/dochelper/baremetalhost.yaml b/pkg/document/testdata/dochelper/baremetalhost.yaml
new file mode 100644
index 000000000..f20e8c0da
--- /dev/null
+++ b/pkg/document/testdata/dochelper/baremetalhost.yaml
@@ -0,0 +1,16 @@
+---
+apiVersion: metal3.io/v1alpha1
+kind: BareMetalHost
+metadata:
+  labels:
+    airshipit.org/ephemeral-node: "true"
+  name: master-0
+spec:
+  online: true
+  bootMACAddress: 00:3b:8b:0c:ec:8b
+  bmc:
+    address: redfish+https://192.168.111.1/v1/Redfish/Foo/Bar
+    credentialsName: master-0-bmc
+  networkData:
+    name: master-0-networkdata
+    namespace: metal3
diff --git a/pkg/document/testdata/dochelper/kustomization.yaml b/pkg/document/testdata/dochelper/kustomization.yaml
new file mode 100644
index 000000000..3935bdb09
--- /dev/null
+++ b/pkg/document/testdata/dochelper/kustomization.yaml
@@ -0,0 +1,3 @@
+resources:
+ - baremetalhost.yaml
+ - secret.yaml
\ No newline at end of file
diff --git a/pkg/document/testdata/dochelper/secret.yaml b/pkg/document/testdata/dochelper/secret.yaml
new file mode 100644
index 000000000..4bafed861
--- /dev/null
+++ b/pkg/document/testdata/dochelper/secret.yaml
@@ -0,0 +1,28 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  labels:
+    airshipit.org/ephemeral-user-data: "true"
+  name: ephemeral-user-data
+type: Opaque
+stringData:
+  userData: cloud-init
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: master-0-bmc
+  namespace: metal3
+type: Opaque
+stringData:
+  username: username
+  password: password
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: master-0-networkdata
+  namespace: metal3
+type: Opaque
+stringData:
+  networkData: some network data
\ No newline at end of file
diff --git a/pkg/document/testdata/selectors/valid/secret.yaml b/pkg/document/testdata/selectors/valid/secret.yaml
index 25a11a87c..f39541cd2 100644
--- a/pkg/document/testdata/selectors/valid/secret.yaml
+++ b/pkg/document/testdata/selectors/valid/secret.yaml
@@ -17,5 +17,4 @@ metadata:
   namespace: validNamespace
 type: Opaque
 stringData:
-  userData: cloud-init
-
+  userData: cloud-init
\ No newline at end of file
diff --git a/pkg/remote/redfish/redfish.go b/pkg/remote/redfish/redfish.go
index 6bacc6289..a20ab81db 100644
--- a/pkg/remote/redfish/redfish.go
+++ b/pkg/remote/redfish/redfish.go
@@ -29,14 +29,18 @@ type RemoteDirect struct {
 
 	// Redfish Client implementation
 	RedfishAPI redfishApi.RedfishAPI
+
+	// optional Username Authentication
+	Username string
+
+	// optional Password
+	Password string
 }
 
 // Top level function to handle Redfish remote direct
 func (cfg RemoteDirect) DoRemoteDirect() error {
 	alog.Debugf("Using Redfish Endpoint: '%s'", cfg.RemoteURL.String())
 
-	/* TODO: Add Authentication when redfish library supports it. */
-
 	/* Get system details */
 	systemID := cfg.EphemeralNodeID
 	system, _, err := cfg.RedfishAPI.GetSystem(cfg.Context, systemID)
@@ -79,10 +83,12 @@ func (cfg RemoteDirect) DoRemoteDirect() error {
 	return nil
 }
 
-// Creates a new Redfish remote direct client.
-func NewRedfishRemoteDirectClient(ctx context.Context,
+// NewRedfishRemoteDirectClient creates a new Redfish remote direct client.
+func NewRedfishRemoteDirectClient(
 	remoteURL string,
 	ephNodeID string,
+	username string,
+	password string,
 	isoPath string,
 	insecure bool,
 	useproxy bool,
@@ -101,6 +107,17 @@ func NewRedfishRemoteDirectClient(ctx context.Context,
 			}
 	}
 
+	var ctx context.Context
+	if username != "" && password != "" {
+		ctx = context.WithValue(
+			context.Background(),
+			redfishClient.ContextBasicAuth,
+			redfishClient.BasicAuth{UserName: username, Password: password},
+		)
+	} else {
+		ctx = context.Background()
+	}
+
 	if isoPath == "" {
 		return RemoteDirect{},
 			ErrRedfishMissingConfig{
diff --git a/pkg/remote/redfish/redfish_test.go b/pkg/remote/redfish/redfish_test.go
index a1765c084..29914122a 100644
--- a/pkg/remote/redfish/redfish_test.go
+++ b/pkg/remote/redfish/redfish_test.go
@@ -28,37 +28,44 @@ func TestRedfishRemoteDirectNormal(t *testing.T) {
 
 	systemID := computerSystemID
 	httpResp := &http.Response{StatusCode: 200}
-	m.On("GetSystem", context.Background(), systemID).Times(1).
+
+	ctx := context.WithValue(
+		context.Background(),
+		redfishClient.ContextBasicAuth,
+		redfishClient.BasicAuth{UserName: "username", Password: "password"},
+	)
+
+	m.On("GetSystem", ctx, systemID).Times(1).
 		Return(getTestSystem(), httpResp, nil)
-	m.On("InsertVirtualMedia", context.Background(), "manager-1", "Cd", mock.Anything).
+	m.On("InsertVirtualMedia", ctx, "manager-1", "Cd", mock.Anything).
 		Return(redfishClient.RedfishError{}, httpResp, nil)
 
-	m.On("GetSystem", context.Background(), systemID).Times(1).
+	m.On("GetSystem", ctx, systemID).Times(1).
 		Return(getTestSystem(), httpResp, nil)
 	systemReq := redfishClient.ComputerSystem{
 		Boot: redfishClient.Boot{
 			BootSourceOverrideTarget: redfishClient.BOOTSOURCE_CD,
 		},
 	}
-	m.On("SetSystem", context.Background(), systemID, systemReq).
+	m.On("SetSystem", ctx, systemID, systemReq).
 		Times(1).
 		Return(redfishClient.ComputerSystem{}, httpResp, nil)
 
 	resetReq := redfishClient.ResetRequestBody{}
 	resetReq.ResetType = redfishClient.RESETTYPE_FORCE_OFF
-	m.On("ResetSystem", context.Background(), systemID, resetReq).
+	m.On("ResetSystem", ctx, systemID, resetReq).
 		Times(1).
 		Return(redfishClient.RedfishError{}, httpResp, nil)
 
-	m.On("GetSystem", context.Background(), systemID).Times(1).
+	m.On("GetSystem", ctx, systemID).Times(1).
 		Return(redfishClient.ComputerSystem{PowerState: redfishClient.POWERSTATE_OFF}, httpResp, nil)
 
 	resetReq.ResetType = redfishClient.RESETTYPE_ON
-	m.On("ResetSystem", context.Background(), systemID, resetReq).
+	m.On("ResetSystem", ctx, systemID, resetReq).
 		Times(1).
 		Return(redfishClient.RedfishError{}, httpResp, nil)
 
-	m.On("GetSystem", context.Background(), systemID).Times(1).
+	m.On("GetSystem", ctx, systemID).Times(1).
 		Return(redfishClient.ComputerSystem{PowerState: redfishClient.POWERSTATE_ON}, httpResp, nil)
 
 	rDCfg := getDefaultRedfishRemoteDirectObj(t, m)
@@ -72,13 +79,19 @@ func TestRedfishRemoteDirectInvalidSystemId(t *testing.T) {
 	m := &redfishMocks.RedfishAPI{}
 	defer m.AssertExpectations(t)
 
+	ctx := context.WithValue(
+		context.Background(),
+		redfishClient.ContextBasicAuth,
+		redfishClient.BasicAuth{UserName: "username", Password: "password"},
+	)
+
 	systemID := "invalid-server"
 	localRDCfg := getDefaultRedfishRemoteDirectObj(t, m)
 
 	localRDCfg.EphemeralNodeID = systemID
 
 	realErr := fmt.Errorf("%s system do not exist", systemID)
-	m.On("GetSystem", context.Background(), systemID).
+	m.On("GetSystem", ctx, systemID).
 		Times(1).
 		Return(redfishClient.ComputerSystem{}, nil, realErr)
 
@@ -92,10 +105,16 @@ func TestRedfishRemoteDirectGetSystemNetworkError(t *testing.T) {
 	m := &redfishMocks.RedfishAPI{}
 	defer m.AssertExpectations(t)
 
+	ctx := context.WithValue(
+		context.Background(),
+		redfishClient.ContextBasicAuth,
+		redfishClient.BasicAuth{UserName: "username", Password: "password"},
+	)
+
 	systemID := computerSystemID
 	realErr := fmt.Errorf("server request timeout")
 	httpResp := &http.Response{StatusCode: 408}
-	m.On("GetSystem", context.Background(), systemID).
+	m.On("GetSystem", ctx, systemID).
 		Times(1).
 		Return(redfishClient.ComputerSystem{}, httpResp, realErr)
 
@@ -111,6 +130,12 @@ func TestRedfishRemoteDirectInvalidIsoPath(t *testing.T) {
 	m := &redfishMocks.RedfishAPI{}
 	defer m.AssertExpectations(t)
 
+	ctx := context.WithValue(
+		context.Background(),
+		redfishClient.ContextBasicAuth,
+		redfishClient.BasicAuth{UserName: "username", Password: "password"},
+	)
+
 	systemID := computerSystemID
 	rDCfg := getDefaultRedfishRemoteDirectObj(t, m)
 	localRDCfg := rDCfg
@@ -118,11 +143,11 @@ func TestRedfishRemoteDirectInvalidIsoPath(t *testing.T) {
 
 	realErr := redfishClient.GenericOpenAPIError{}
 	httpResp := &http.Response{StatusCode: 500}
-	m.On("GetSystem", context.Background(), systemID).
+	m.On("GetSystem", ctx, systemID).
 		Times(1).
 		Return(getTestSystem(), nil, nil)
 
-	m.On("InsertVirtualMedia", context.Background(), "manager-1", "Cd", mock.Anything).
+	m.On("InsertVirtualMedia", ctx, "manager-1", "Cd", mock.Anything).
 		Return(redfishClient.RedfishError{}, httpResp, realErr)
 
 	err := localRDCfg.DoRemoteDirect()
@@ -135,6 +160,12 @@ func TestRedfishRemoteDirectCdDvdNotAvailableInBootSources(t *testing.T) {
 	m := &redfishMocks.RedfishAPI{}
 	defer m.AssertExpectations(t)
 
+	ctx := context.WithValue(
+		context.Background(),
+		redfishClient.ContextBasicAuth,
+		redfishClient.BasicAuth{UserName: "username", Password: "password"},
+	)
+
 	systemID := computerSystemID
 	invalidSystem := getTestSystem()
 	invalidSystem.Boot.BootSourceOverrideTargetRedfishAllowableValues = []redfishClient.BootSource{
@@ -142,10 +173,10 @@ func TestRedfishRemoteDirectCdDvdNotAvailableInBootSources(t *testing.T) {
 		redfishClient.BOOTSOURCE_PXE,
 	}
 
-	m.On("GetSystem", context.Background(), systemID).
+	m.On("GetSystem", ctx, systemID).
 		Return(invalidSystem, nil, nil)
 
-	m.On("InsertVirtualMedia", context.Background(), "manager-1", "Cd", mock.Anything).
+	m.On("InsertVirtualMedia", ctx, "manager-1", "Cd", mock.Anything).
 		Return(redfishClient.RedfishError{}, nil, nil)
 
 	rDCfg := getDefaultRedfishRemoteDirectObj(t, m)
@@ -160,15 +191,21 @@ func TestRedfishRemoteDirectSetSystemBootSourceFailed(t *testing.T) {
 	m := &redfishMocks.RedfishAPI{}
 	defer m.AssertExpectations(t)
 
+	ctx := context.WithValue(
+		context.Background(),
+		redfishClient.ContextBasicAuth,
+		redfishClient.BasicAuth{UserName: "username", Password: "password"},
+	)
+
 	systemID := computerSystemID
 	httpSuccResp := &http.Response{StatusCode: 200}
-	m.On("GetSystem", context.Background(), systemID).
+	m.On("GetSystem", ctx, systemID).
 		Return(getTestSystem(), httpSuccResp, nil)
 
-	m.On("InsertVirtualMedia", context.Background(), "manager-1", "Cd", mock.Anything).
+	m.On("InsertVirtualMedia", ctx, "manager-1", "Cd", mock.Anything).
 		Return(redfishClient.RedfishError{}, httpSuccResp, nil)
 
-	m.On("SetSystem", context.Background(), systemID, mock.Anything).
+	m.On("SetSystem", ctx, systemID, mock.Anything).
 		Times(1).
 		Return(redfishClient.ComputerSystem{}, &http.Response{StatusCode: 401},
 			redfishClient.GenericOpenAPIError{})
@@ -185,21 +222,27 @@ func TestRedfishRemoteDirectSystemRebootFailed(t *testing.T) {
 	m := &redfishMocks.RedfishAPI{}
 	defer m.AssertExpectations(t)
 
+	ctx := context.WithValue(
+		context.Background(),
+		redfishClient.ContextBasicAuth,
+		redfishClient.BasicAuth{UserName: "username", Password: "password"},
+	)
+
 	systemID := computerSystemID
 	httpSuccResp := &http.Response{StatusCode: 200}
-	m.On("GetSystem", context.Background(), systemID).
+	m.On("GetSystem", ctx, systemID).
 		Return(getTestSystem(), httpSuccResp, nil)
 
-	m.On("InsertVirtualMedia", context.Background(), mock.Anything, mock.Anything, mock.Anything).
+	m.On("InsertVirtualMedia", ctx, mock.Anything, mock.Anything, mock.Anything).
 		Return(redfishClient.RedfishError{}, httpSuccResp, nil)
 
-	m.On("SetSystem", context.Background(), systemID, mock.Anything).
+	m.On("SetSystem", ctx, systemID, mock.Anything).
 		Times(1).
 		Return(redfishClient.ComputerSystem{}, httpSuccResp, nil)
 
 	resetReq := redfishClient.ResetRequestBody{}
 	resetReq.ResetType = redfishClient.RESETTYPE_FORCE_OFF
-	m.On("ResetSystem", context.Background(), systemID, resetReq).
+	m.On("ResetSystem", ctx, systemID, resetReq).
 		Times(1).
 		Return(redfishClient.RedfishError{}, &http.Response{StatusCode: 401},
 			redfishClient.GenericOpenAPIError{})
@@ -244,9 +287,10 @@ func TestNewRedfishRemoteDirectClient(t *testing.T) {
 	defer m.AssertExpectations(t)
 
 	_, err := NewRedfishRemoteDirectClient(
-		context.Background(),
 		defaultURL,
 		computerSystemID,
+		"username",
+		"password",
 		"/tmp/test.iso",
 		true,
 		false,
@@ -255,9 +299,10 @@ func TestNewRedfishRemoteDirectClient(t *testing.T) {
 
 	// Test with empty remote URL
 	_, err = NewRedfishRemoteDirectClient(
-		context.Background(),
 		"",
 		computerSystemID,
+		"username",
+		"password",
 		"/tmp/test.iso",
 		false,
 		false,
@@ -267,9 +312,10 @@ func TestNewRedfishRemoteDirectClient(t *testing.T) {
 
 	// Test with empty ephemeral NodeID
 	_, err = NewRedfishRemoteDirectClient(
-		context.Background(),
 		defaultURL,
 		"",
+		"username",
+		"password",
 		"/tmp/test.iso",
 		false,
 		false,
@@ -279,9 +325,10 @@ func TestNewRedfishRemoteDirectClient(t *testing.T) {
 
 	// Test with empty Iso Path
 	_, err = NewRedfishRemoteDirectClient(
-		context.Background(),
 		defaultURL,
 		computerSystemID,
+		"username",
+		"password",
 		"",
 		false,
 		false,
@@ -294,9 +341,10 @@ func getDefaultRedfishRemoteDirectObj(t *testing.T, api redfishAPI.RedfishAPI) R
 	t.Helper()
 
 	rDCfg, err := NewRedfishRemoteDirectClient(
-		context.Background(),
 		defaultURL,
 		computerSystemID,
+		"username",
+		"password",
 		"/tmp/test.iso",
 		false,
 		false,
diff --git a/pkg/remote/remote_direct.go b/pkg/remote/remote_direct.go
index 0a328ef21..0c8784d6c 100644
--- a/pkg/remote/remote_direct.go
+++ b/pkg/remote/remote_direct.go
@@ -1,7 +1,6 @@
 package remote
 
 import (
-	"context"
 	"fmt"
 	"net/url"
 	"strings"
@@ -23,7 +22,11 @@ type Client interface {
 }
 
 // Get remotedirect client based on config
-func getRemoteDirectClient(remoteConfig *config.RemoteDirect, remoteURL string) (Client, error) {
+func getRemoteDirectClient(
+	remoteConfig *config.RemoteDirect,
+	remoteURL string,
+	username string,
+	password string) (Client, error) {
 	var client Client
 	switch remoteConfig.RemoteType {
 	case AirshipRemoteTypeRedfish:
@@ -44,9 +47,10 @@ func getRemoteDirectClient(remoteConfig *config.RemoteDirect, remoteURL string)
 		nodeID := urlPath[len(urlPath)-1]
 
 		client, err = redfish.NewRedfishRemoteDirectClient(
-			context.Background(),
 			baseURL,
 			nodeID,
+			username,
+			password,
 			remoteConfig.IsoURL,
 			remoteConfig.Insecure,
 			remoteConfig.UseProxy,
@@ -63,56 +67,60 @@ func getRemoteDirectClient(remoteConfig *config.RemoteDirect, remoteURL string)
 	return client, nil
 }
 
-func getRemoteDirectConfig(settings *environment.AirshipCTLSettings) (*config.RemoteDirect, string, error) {
+func getRemoteDirectConfig(settings *environment.AirshipCTLSettings) (
+	remoteConfig *config.RemoteDirect,
+	remoteURL string,
+	username string,
+	password string,
+	err error) {
 	cfg := settings.Config()
 	bootstrapSettings, err := cfg.CurrentContextBootstrapInfo()
 	if err != nil {
-		return nil, "", err
+		return nil, "", "", "", err
 	}
 
-	remoteConfig := bootstrapSettings.RemoteDirect
+	remoteConfig = bootstrapSettings.RemoteDirect
 	if remoteConfig == nil {
-		return nil, "", config.ErrMissingConfig{What: "RemoteDirect options not defined in bootstrap config"}
+		return nil, "", "", "", config.ErrMissingConfig{What: "RemoteDirect options not defined in bootstrap config"}
 	}
 
-	root, err := cfg.CurrentContextEntryPoint(config.Ephemeral, "")
+	bundlePath, err := cfg.CurrentContextEntryPoint(config.Ephemeral, "")
 	if err != nil {
-		return nil, "", err
+		return nil, "", "", "", err
 	}
 
-	docBundle, err := document.NewBundleByPath(root)
+	docBundle, err := document.NewBundleByPath(bundlePath)
 	if err != nil {
-		return nil, "", err
+		return nil, "", "", "", err
 	}
 
 	selector := document.NewEphemeralBMHSelector()
-	docs, err := docBundle.Select(selector)
+	doc, err := docBundle.SelectOne(selector)
 	if err != nil {
-		return nil, "", err
-	}
-	if len(docs) == 0 {
-		return nil, "", document.ErrDocNotFound{
-			Selector: selector,
-		}
+		return nil, "", "", "", err
 	}
 
-	// NOTE If filter returned more than one document chose first
-	remoteURL, err := docs[0].GetString("spec.bmc.address")
+	remoteURL, err = document.GetBMHBMCAddress(doc)
 	if err != nil {
-		return nil, "", err
+		return nil, "", "", "", err
 	}
 
-	return remoteConfig, remoteURL, nil
+	username, password, err = document.GetBMHBMCCredentials(doc, docBundle)
+	if err != nil {
+		return nil, "", "", "", err
+	}
+
+	return remoteConfig, remoteURL, username, password, nil
 }
 
 // Top level function to execute remote direct based on remote type
 func DoRemoteDirect(settings *environment.AirshipCTLSettings) error {
-	remoteConfig, remoteURL, err := getRemoteDirectConfig(settings)
+	remoteConfig, remoteURL, username, password, err := getRemoteDirectConfig(settings)
 	if err != nil {
 		return err
 	}
 
-	client, err := getRemoteDirectClient(remoteConfig, remoteURL)
+	client, err := getRemoteDirectClient(remoteConfig, remoteURL, username, password)
 	if err != nil {
 		return err
 	}