Repository: aws/secrets-store-csi-driver-provider-aws

Issue:
Unable to fetch credentials from EKS Auth: operation error EKS Auth: AssumeRoleForPodIdentity
**Describe the bug**
When I am trying to mount secrets from Secrets Manager via the driver, I see the following errors in the pod logs:

kube-system/eks-pod-identity-agent-hkjwr:
`
eks-pod-identity-agent {"client-addr":"192.168.146.19:36642","cluster-name":"eks-fi-eu1-d","level":"info","msg":"Calling EKS Auth to fetch credentials","time":"2025-05-27T16:22:23Z"} 
eks-pod-identity-agent {"client-addr":"192.168.146.19:36642","cluster-name":"eks-fi-eu1-d","level":"error","msg":"Error fetching credentials: error getting credentials to cache: unable to fetch credentials from EKS Auth: operation error EKS Auth: AssumeRoleForPodIdentity, https response error StatusCode: 0, RequestID: , canceled, context canceled","operation":"AssumeRoleForPodIdentity","request-id":"","service":"EKS Auth","time":"2025-05-27T16:22:23Z"}
`

kube-system/secrets-store-csi-driver-provider-aws-qmtj2
`
I0527 16:24:25.713506       1 auth.go:82] Using Pod Identity for authentication in namespace: aa, service account: lowcodeapps-service-account
W0527 16:24:25.831530       1 pod_identity_credential_provider.go:142] IPv4 endpoint attempt failed: HTTP request to pod identity agent failed: Get "http://169.254.170.23/v1/credentials": context deadline exceeded (Client.Timeout exceeded while awaiting headers).
`

**To Reproduce**

Steps to reproduce the behavior:
Follow the steps on https://github.com/aws/secrets-store-csi-driver-provider-aws/tree/main?tab=readme-ov-file#option-2-using-eks-pod-identity

Do you also notice this bug when using a different secrets store provider (Vault/Azure/GCP...)? **No**

**Expected behavior**
Secrets get mounted

**Environment:**
AWS EKS Cluster 1.32
secrets-store-csi-driver 1.5.0
secrets-store-csi-driver-provider-aws-1.0.1

**Additional context**
I am not sure if this is some misconfiguration on my side or a bug in the provider. When I deploy a normal pod and attach a Kubernetes ServiceAccount that has a Pod Identity Association, the Role claim works fine. I see the positive logs in the pod identity agent and can access the AWS services as described in the respective policy.

For mounting the secrets though I get the errors above. With this I assume that network access is fine as the eks pod identity agent works for the normal pods with Pod Identity Association.

I was also wondering if the secrets-store-csi-driver-provider-aws service account needs a Pod Identity Association or if it takes the association of the "target pod" where the secrets get mounted to.


Discussion:
@simonmarty: > kube-system/secrets-store-csi-driver-provider-aws-qmtj2
I0527 16:24:25.713506       1 auth.go:82] Using Pod Identity for authentication in namespace: aa, service account: lowcodeapps-service-account W0527 16:24:25.831530       1 pod_identity_credential_provider.go:142] IPv4 endpoint attempt failed: HTTP request to pod identity agent failed: Get "http://169.254.170.23/v1/credentials": context deadline exceeded (Client.Timeout exceeded while awaiting headers).

We're tracking this here https://github.com/aws/secrets-store-csi-driver-provider-aws/pull/458

> I was also wondering if the secrets-store-csi-driver-provider-aws service account needs a Pod Identity Association or if it takes the association of the "target pod" where the secrets get mounted to.

You create a pod identity that associates an IAM role to a service account

https://github.com/aws/secrets-store-csi-driver-provider-aws?tab=readme-ov-file#option-2-using-eks-pod-identity

https://github.com/search?q=repo%3Aaws%2Fsecrets-store-csi-driver-provider-aws%20nginx-pod-identity-deployment-sa&type=code

@Hymian7: Thanks for pointing me to the PR. Is there any known hotfix until the PR is merged?

Also for the service account, am I correct that there is no pod identity association for the pods of the daemonset, only for the target pod (nginx in the example)?@simonmarty: We're working on making the timeout mentioned in the PR configurable. A workaround could be to use IRSA until this gets sorted out.

Correct, the pod identity association doesn't need to be configured for the daemon set, only for the subsequent deployments that retrieve secrets.@czapajew: I'm trying to secrets-store-csi-driver-provider-aws with kops managed non eks cluster on aws.
I'm getting 169.254.170.23 timeout. Is there anything what I should do or I'm on wrong path?@simonmarty: My team doesn't provide support for non-EKS clusters. The Pod Identity Agent calls the EKS auth endpoint to get IAM credentials. You cannot use it unless you're running either EKS or EKS Anywhere, to the best of my knowledge. @pixiono: We have the same problem. We use a normal EKS setup, but we also quickly reach the timeout limit. We increased the timeout limit in the source code as a test and manually built an image, which worked.

The only thing I can think of that might be causing the problem is that we are using a VPC endpoint for eks-auth, but this has not been a problem with other services so far.

Unfortunately, this prevents us from using the CSI driver. Do you have any idea when the PR will be noticed?@simonmarty: The PR is in code review. It is actively being worked on. Thanks for your patience.

Solution patch:
diff --git a/README.md b/README.md
index 4e32862..058b2ef 100644
--- a/README.md
+++ b/README.md
@@ -316,6 +316,14 @@ To mount each secret on each pod, the AWS CSI provider lookups the region of the
 
 If you use Helm chart to install the provider, append the `--set-json 'k8sThrottlingParams={"qps": "<custom qps>", "burst": "<custom qps>"}'` flag in the install step.
 
+### HTTP timeout for Pod Identity
+
+In order to configure the HTTP timeout for Pod Identity authentication, pass the `pod-identity-http-timeout` flag during the install step:
+```shell
+helm install ... --pod-identity-http-timeout=250ms
+```
+The timeout value must be a valid Go duration string (e.g. `2s`, `500ms`). The timeout value uses the [AWS SDK default](https://github.com/aws/aws-sdk-go-v2/blob/main/aws/transport/http/client.go#L33) by default.
+
 ### Security Considerations
 
 The AWS Secrets Manager and Config Provider provides compatibility for legacy applications that access secrets as mounted files in the pod. Security conscious applications should use the native AWS APIs to fetch secrets and optionally cache them in memory rather than storing them in the file system.
diff --git a/auth/auth.go b/auth/auth.go
index 904e190..1869c84 100644
--- a/auth/auth.go
+++ b/auth/auth.go
@@ -9,6 +9,7 @@ package auth
 
 import (
 	"context"
+	"time"
 
 	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go-v2/config"
@@ -32,10 +33,12 @@ var ProviderVersion = "unknown"
 // Auth is the main entry point to retrieve an AWS config. The caller
 // initializes a new Auth object with NewAuth passing the region, namespace, pod name,
 // K8s service account and usePodIdentity flag  (and request context). The caller can then obtain AWS
-// config by calling GetAWSConfig.
+// config by calling GetAWSConfig. podIdentityHttpTimeout is used to specify the HTTP timeout used for
+// Pod Identity auth
 type Auth struct {
 	region, nameSpace, svcAcc, podName, preferredAddressType string
 	usePodIdentity                                           bool
+	podIdentityHttpTimeout                                   *time.Duration
 	k8sClient                                                k8sv1.CoreV1Interface
 	stsClient                                                stscreds.AssumeRoleWithWebIdentityAPIClient
 }
@@ -44,6 +47,7 @@ type Auth struct {
 func NewAuth(
 	region, nameSpace, svcAcc, podName, preferredAddressType string,
 	usePodIdentity bool,
+	podIdentityHttpTimeout *time.Duration,
 	k8sClient k8sv1.CoreV1Interface,
 ) (auth *Auth, e error) {
 	var stsClient *sts.Client
@@ -61,14 +65,15 @@ func NewAuth(
 	}
 
 	return &Auth{
-		region:               region,
-		nameSpace:            nameSpace,
-		svcAcc:               svcAcc,
-		podName:              podName,
-		preferredAddressType: preferredAddressType,
-		usePodIdentity:       usePodIdentity,
-		k8sClient:            k8sClient,
-		stsClient:            stsClient,
+		region:                 region,
+		nameSpace:              nameSpace,
+		svcAcc:                 svcAcc,
+		podName:                podName,
+		preferredAddressType:   preferredAddressType,
+		usePodIdentity:         usePodIdentity,
+		podIdentityHttpTimeout: podIdentityHttpTimeout,
+		k8sClient:              k8sClient,
+		stsClient:              stsClient,
 	}, nil
 
 }
@@ -81,8 +86,11 @@ func (p Auth) GetAWSConfig(ctx context.Context) (aws.Config, error) {
 
 	if p.usePodIdentity {
 		klog.Infof("Using Pod Identity for authentication in namespace: %s, service account: %s", p.nameSpace, p.svcAcc)
+		if p.podIdentityHttpTimeout != nil {
+			klog.Infof("Using custom Pod Identity timeout: %v", *p.podIdentityHttpTimeout)
+		}
 		var err error
-		credProvider, err = credential_provider.NewPodIdentityCredentialProvider(p.region, p.nameSpace, p.svcAcc, p.podName, p.preferredAddressType, p.k8sClient)
+		credProvider, err = credential_provider.NewPodIdentityCredentialProvider(p.region, p.nameSpace, p.svcAcc, p.podName, p.preferredAddressType, p.podIdentityHttpTimeout, p.k8sClient)
 		if err != nil {
 			return aws.Config{}, err
 		}
diff --git a/charts/secrets-store-csi-driver-provider-aws/templates/daemonset.yaml b/charts/secrets-store-csi-driver-provider-aws/templates/daemonset.yaml
index d7e0b9d..ba805c4 100644
--- a/charts/secrets-store-csi-driver-provider-aws/templates/daemonset.yaml
+++ b/charts/secrets-store-csi-driver-provider-aws/templates/daemonset.yaml
@@ -49,6 +49,9 @@ spec:
             - --burst={{ .Values.k8sThrottlingParams.burst }}
             {{- end }}
             {{- end }}
+            {{- if .Values.podIdentityHttpTimeout }}
+            - --pod-identity-http-timeout={{ .Values.podIdentityHttpTimeout }}
+            {{- end }}
           resources:
 {{ toYaml .Values.resources | indent 12 }}
           securityContext:
diff --git a/charts/secrets-store-csi-driver-provider-aws/values.yaml b/charts/secrets-store-csi-driver-provider-aws/values.yaml
index 21e4bca..6a6188b 100644
--- a/charts/secrets-store-csi-driver-provider-aws/values.yaml
+++ b/charts/secrets-store-csi-driver-provider-aws/values.yaml
@@ -45,6 +45,8 @@ securityContext:
 
 useFipsEndpoint: false
 
+podIdentityHttpTimeout:
+
 dnsConfig: {}
 
 secrets-store-csi-driver:
diff --git a/credential_provider/pod_identity_credential_provider.go b/credential_provider/pod_identity_credential_provider.go
index db8ea74..41daaa9 100644
--- a/credential_provider/pod_identity_credential_provider.go
+++ b/credential_provider/pod_identity_credential_provider.go
@@ -3,7 +3,6 @@ package credential_provider
 import (
 	"context"
 	"fmt"
-	"net/http"
 	"strings"
 	"time"
 
@@ -13,6 +12,7 @@ import (
 	"github.com/aws/aws-sdk-go-v2/config"
 	"github.com/aws/aws-sdk-go-v2/credentials/endpointcreds"
 
+	awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
 	authv1 "k8s.io/api/authentication/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	k8sv1 "k8s.io/client-go/kubernetes/typed/core/v1"
@@ -22,7 +22,6 @@ const (
 	podIdentityAudience = "pods.eks.amazonaws.com"
 	defaultIPv4Endpoint = "http://169.254.170.23/v1/credentials"
 	defaultIPv6Endpoint = "http://[fd00:ec2::23]/v1/credentials"
-	httpTimeout         = 100 * time.Millisecond
 )
 
 var (
@@ -74,11 +73,12 @@ type PodIdentityCredentialProvider struct {
 	region               string
 	preferredAddressType string
 	fetcher              endpointcreds.AuthTokenProvider
-	httpClient           *http.Client
+	httpClient           *awshttp.BuildableClient
 }
 
 func NewPodIdentityCredentialProvider(
 	region, nameSpace, svcAcc, podName, preferredAddressType string,
+	podIdentityHttpTimeout *time.Duration,
 	k8sClient k8sv1.CoreV1Interface,
 ) (ConfigProvider, error) {
 	// Add validation if needed
@@ -89,14 +89,17 @@ func NewPodIdentityCredentialProvider(
 		return nil, fmt.Errorf("k8s client cannot be nil")
 	}
 
-	return &PodIdentityCredentialProvider{
+	pod_identity := PodIdentityCredentialProvider{
 		region:               region,
 		preferredAddressType: preferredAddressType,
 		fetcher:              newPodIdentityTokenFetcher(nameSpace, svcAcc, podName, k8sClient),
-		httpClient: &http.Client{
-			Timeout: httpTimeout,
-		},
-	}, nil
+	}
+
+	if podIdentityHttpTimeout != nil {
+		pod_identity.httpClient = awshttp.NewBuildableClient().WithTimeout(*podIdentityHttpTimeout)
+	}
+
+	return &pod_identity, nil
 }
 
 func parseAddressPreference(preferredAddressType string) string {
@@ -143,7 +146,10 @@ func (p *PodIdentityCredentialProvider) getConfigWithEndpoint(ctx context.Contex
 	provider := endpointcreds.New(endpoint,
 		func(opts *endpointcreds.Options) {
 			opts.AuthorizationTokenProvider = p.fetcher
-			opts.HTTPClient = p.httpClient
+
+			if p.httpClient != nil {
+				opts.HTTPClient = p.httpClient
+			}
 		},
 	)
 	return config.LoadDefaultConfig(ctx,
diff --git a/main.go b/main.go
index d1c4372..d6d4db2 100644
--- a/main.go
+++ b/main.go
@@ -7,6 +7,7 @@ import (
 	"os"
 	"os/signal"
 	"syscall"
+	"time"
 
 	"google.golang.org/grpc"
 	"k8s.io/client-go/kubernetes"
@@ -20,12 +21,37 @@ import (
 )
 
 var (
-	endpointDir        = flag.String("provider-volume", "/var/run/secrets-store-csi-providers", "Rendezvous directory for provider socket")
-	driverWriteSecrets = flag.Bool("driver-writes-secrets", false, "The driver will do the write instead of the plugin")
-	qps                = flag.Int("qps", 5, "Maximum query per second to the Kubernetes API server. To mount the requested secret on the pod, the AWS CSI provider lookups the region of the pod and the role ARN associated with the service account by calling the K8s APIs. Increase the value if the provider is throttled by client-side limit to the API server.")
-	burst              = flag.Int("burst", 10, "Maximum burst for throttle. To mount the requested secret on the pod, the AWS CSI provider lookups the region of the pod and the role ARN associated with the service account by calling the K8s APIs. Increase the value if the provider is throttled by client-side limit to the API server.")
+	endpointDir            = flag.String("provider-volume", "/var/run/secrets-store-csi-providers", "Rendezvous directory for provider socket")
+	driverWriteSecrets     = flag.Bool("driver-writes-secrets", false, "The driver will do the write instead of the plugin")
+	qps                    = flag.Int("qps", 5, "Maximum query per second to the Kubernetes API server. To mount the requested secret on the pod, the AWS CSI provider lookups the region of the pod and the role ARN associated with the service account by calling the K8s APIs. Increase the value if the provider is throttled by client-side limit to the API server.")
+	burst                  = flag.Int("burst", 10, "Maximum burst for throttle. To mount the requested secret on the pod, the AWS CSI provider lookups the region of the pod and the role ARN associated with the service account by calling the K8s APIs. Increase the value if the provider is throttled by client-side limit to the API server.")
+	podIdentityHttpTimeout = flag.String("pod-identity-http-timeout", "", "The HTTP timeout threshold for Pod Identity authentication.")
 )
 
+// parsePodIdentityHttpTimeout parses and validates the HTTP timeout for Pod Identity authentication
+func parsePodIdentityHttpTimeout(timeoutStr string) *time.Duration {
+	if timeoutStr == "" {
+		return nil
+	}
+
+	duration, err := time.ParseDuration(timeoutStr)
+	if err != nil {
+		klog.Errorf("failed to parse podIdentityHttpTimeout value '%s': %v, using default SDK value", timeoutStr, err)
+		return nil
+	}
+
+	if duration <= 0 {
+		klog.Errorf("podIdentityHttpTimeout must be positive, got: %v, using default SDK value", duration)
+		return nil
+	}
+
+	if duration > 30*time.Second {
+		klog.Warningf("podIdentityHttpTimeout value %v is unusually high, consider using a smaller value", duration)
+	}
+
+	return &duration
+}
+
 // Main entry point for the Secret Store CSI driver AWS provider. This main
 // rountine starts up the gRPC server that will listen for incoming mount
 // requests.
@@ -73,7 +99,10 @@ func main() {
 		os.Remove(endpoint)
 	}()
 
-	providerSrv, err := server.NewServer(provider.NewSecretProviderFactory, clientset.CoreV1(), *driverWriteSecrets)
+	// Parse and validate HTTP timeout
+	podIdentityHttpTimeoutDuration := parsePodIdentityHttpTimeout(*podIdentityHttpTimeout)
+
+	providerSrv, err := server.NewServer(provider.NewSecretProviderFactory, clientset.CoreV1(), *driverWriteSecrets, podIdentityHttpTimeoutDuration)
 	if err != nil {
 		klog.Fatalf("Could not create server. error: %v", err)
 	}
diff --git a/server/server.go b/server/server.go
index 94adb26..65f989d 100644
--- a/server/server.go
+++ b/server/server.go
@@ -14,6 +14,7 @@ import (
 	"os"
 	"strconv"
 	"strings"
+	"time"
 
 	"github.com/aws/aws-sdk-go-v2/aws"
 
@@ -52,9 +53,10 @@ const (
 // during the mount of any one secret no secrets are written to the mount point.
 type CSIDriverProviderServer struct {
 	*grpc.Server
-	secretProviderFactory provider.ProviderFactoryFactory
-	k8sClient             k8sv1.CoreV1Interface
-	driverWriteSecrets    bool
+	secretProviderFactory  provider.ProviderFactoryFactory
+	k8sClient              k8sv1.CoreV1Interface
+	driverWriteSecrets     bool
+	podIdentityHttpTimeout *time.Duration
 }
 
 // Factory function to create the server to handle incoming mount requests.
@@ -62,12 +64,14 @@ func NewServer(
 	secretProviderFact provider.ProviderFactoryFactory,
 	k8client k8sv1.CoreV1Interface,
 	driverWriteSecrets bool,
+	podIdentityHttpTimeout *time.Duration,
 ) (srv *CSIDriverProviderServer, e error) {
 
 	return &CSIDriverProviderServer{
-		secretProviderFactory: secretProviderFact,
-		k8sClient:             k8client,
-		driverWriteSecrets:    driverWriteSecrets,
+		secretProviderFactory:  secretProviderFact,
+		k8sClient:              k8client,
+		driverWriteSecrets:     driverWriteSecrets,
+		podIdentityHttpTimeout: podIdentityHttpTimeout,
 	}, nil
 
 }
@@ -148,7 +152,7 @@ func (s *CSIDriverProviderServer) Mount(ctx context.Context, req *v1alpha1.Mount
 		}
 	}
 
-	awsConfigs, err := s.getAwsConfigs(ctx, nameSpace, svcAcct, regions, usePodIdentity, podName, preferredAddressType)
+	awsConfigs, err := s.getAwsConfigs(ctx, nameSpace, svcAcct, regions, usePodIdentity, podName, preferredAddressType, s.podIdentityHttpTimeout)
 	if err != nil {
 		return nil, err
 	}
@@ -232,12 +236,12 @@ func (s *CSIDriverProviderServer) getAwsRegions(ctx context.Context, region, bac
 // Gets the pod's AWS creds for each lookup region
 // Establishes the connection using Aws cred for each lookup region
 // If at least one config is not created, error will be thrown
-func (s *CSIDriverProviderServer) getAwsConfigs(ctx context.Context, nameSpace, svcAcct string, lookupRegionList []string, usePodIdentity bool, podName string, preferredAddressType string) (response []aws.Config, err error) {
+func (s *CSIDriverProviderServer) getAwsConfigs(ctx context.Context, nameSpace, svcAcct string, lookupRegionList []string, usePodIdentity bool, podName string, preferredAddressType string, podIdentityHttpTimeout *time.Duration) (response []aws.Config, err error) {
 	// Get the pod's AWS creds for each lookup region.
 	var awsConfigsList []aws.Config
 
 	for _, region := range lookupRegionList {
-		awsAuth, err := auth.NewAuth(region, nameSpace, svcAcct, podName, preferredAddressType, usePodIdentity, s.k8sClient)
+		awsAuth, err := auth.NewAuth(region, nameSpace, svcAcct, podName, preferredAddressType, usePodIdentity, podIdentityHttpTimeout, s.k8sClient)
 		if err != nil {
 			return nil, fmt.Errorf("%s: %s", region, err)
 		}



Test patch:
diff --git a/auth/auth_test.go b/auth/auth_test.go
index bc6ed53..dc58eb3 100644
--- a/auth/auth_test.go
+++ b/auth/auth_test.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"strings"
 	"testing"
+	"time"
 
 	"github.com/aws/aws-sdk-go-v2/service/sts"
 	"k8s.io/client-go/kubernetes/fake"
@@ -38,18 +39,124 @@ var sessionTests []sessionTest = []sessionTest{
 	},
 }
 
+func TestNewAuth(t *testing.T) {
+	tests := []struct {
+		name                   string
+		region                 string
+		nameSpace              string
+		svcAcc                 string
+		podName                string
+		preferredAddressType   string
+		usePodIdentity         bool
+		podIdentityHttpTimeout time.Duration
+		expectError            bool
+	}{
+		{
+			name:                   "valid auth with pod identity",
+			region:                 "us-west-2",
+			nameSpace:              "default",
+			svcAcc:                 "test-sa",
+			podName:                "test-pod",
+			preferredAddressType:   "ipv4",
+			usePodIdentity:         true,
+			podIdentityHttpTimeout: 100 * time.Millisecond,
+			expectError:            false,
+		},
+		{
+			name:                   "valid auth with IRSA",
+			region:                 "us-east-1",
+			nameSpace:              "kube-system",
+			svcAcc:                 "irsa-sa",
+			podName:                "irsa-pod",
+			preferredAddressType:   "ipv6",
+			usePodIdentity:         false,
+			podIdentityHttpTimeout: 100 * time.Millisecond,
+			expectError:            false,
+		},
+		{
+			name:                   "valid auth with empty preferred address type",
+			region:                 "eu-west-1",
+			nameSpace:              "test-ns",
+			svcAcc:                 "test-sa",
+			podName:                "test-pod",
+			preferredAddressType:   "",
+			usePodIdentity:         true,
+			podIdentityHttpTimeout: 50 * time.Millisecond,
+			expectError:            false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			k8sClient := fake.NewSimpleClientset().CoreV1()
+
+			auth, err := NewAuth(
+				tt.region,
+				tt.nameSpace,
+				tt.svcAcc,
+				tt.podName,
+				tt.preferredAddressType,
+				tt.usePodIdentity,
+				&tt.podIdentityHttpTimeout,
+				k8sClient,
+			)
+
+			if tt.expectError && err == nil {
+				t.Errorf("Expected error but got none")
+			}
+			if !tt.expectError && err != nil {
+				t.Errorf("Unexpected error: %v", err)
+			}
+
+			if !tt.expectError && auth != nil {
+				// Verify all fields are set correctly
+				if auth.region != tt.region {
+					t.Errorf("Expected region %s, got %s", tt.region, auth.region)
+				}
+				if auth.nameSpace != tt.nameSpace {
+					t.Errorf("Expected namespace %s, got %s", tt.nameSpace, auth.nameSpace)
+				}
+				if auth.svcAcc != tt.svcAcc {
+					t.Errorf("Expected service account %s, got %s", tt.svcAcc, auth.svcAcc)
+				}
+				if auth.podName != tt.podName {
+					t.Errorf("Expected pod name %s, got %s", tt.podName, auth.podName)
+				}
+				if auth.preferredAddressType != tt.preferredAddressType {
+					t.Errorf("Expected preferred address type %s, got %s", tt.preferredAddressType, auth.preferredAddressType)
+				}
+				if auth.usePodIdentity != tt.usePodIdentity {
+					t.Errorf("Expected usePodIdentity %v, got %v", tt.usePodIdentity, auth.usePodIdentity)
+				}
+				if *auth.podIdentityHttpTimeout != tt.podIdentityHttpTimeout {
+					t.Errorf("Expected podIdentityHttpTimeout %v, got %v", tt.podIdentityHttpTimeout, auth.podIdentityHttpTimeout)
+				}
+				if auth.k8sClient == nil {
+					t.Error("Expected k8sClient to be set")
+				}
+				if auth.stsClient == nil {
+					t.Error("Expected stsClient to be set")
+				}
+			}
+		})
+	}
+}
+
 func TestGetAWSConfig(t *testing.T) {
 	for _, tstData := range sessionTests {
 		t.Run(tstData.testName, func(t *testing.T) {
 
+			timeout := 100 * time.Millisecond
+
 			auth := &Auth{
-				region:         "someRegion",
-				nameSpace:      "someNamespace",
-				svcAcc:         "someSvcAcc",
-				podName:        "somepod",
-				usePodIdentity: tstData.testPodIdentity,
-				k8sClient:      fake.NewSimpleClientset().CoreV1(),
-				stsClient:      &mockSTS{},
+				region:                 "someRegion",
+				nameSpace:              "someNamespace",
+				svcAcc:                 "someSvcAcc",
+				podName:                "somepod",
+				usePodIdentity:         tstData.testPodIdentity,
+				podIdentityHttpTimeout: &timeout,
+				k8sClient:              fake.NewSimpleClientset().CoreV1(),
+				stsClient:              &mockSTS{},
 			}
 
 			cfg, err := auth.GetAWSConfig(context.Background())
diff --git a/credential_provider/pod_identity_credential_provider_test.go b/credential_provider/pod_identity_credential_provider_test.go
index edc22fe..1e3c95c 100644
--- a/credential_provider/pod_identity_credential_provider_test.go
+++ b/credential_provider/pod_identity_credential_provider_test.go
@@ -8,7 +8,9 @@ import (
 	"net/http/httptest"
 	"strings"
 	"testing"
+	"time"
 
+	awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
 	"k8s.io/client-go/kubernetes/fake"
 	k8sv1 "k8s.io/client-go/kubernetes/typed/core/v1"
 )
@@ -109,7 +111,7 @@ func newPodIdentityCredentialWithMock(t *testing.T, isIPv4 bool, tstData podIden
 		region:               testRegion,
 		preferredAddressType: tstData.preferredEndpoint,
 		fetcher:              newPodIdentityTokenFetcher(testNamespace, testServiceAccount, testPodName, k8sClient),
-		httpClient:           http.DefaultClient,
+		httpClient:           awshttp.NewBuildableClient(),
 	}, respChan
 }
 
@@ -358,6 +360,71 @@ func TestPodIdentityToken(t *testing.T) {
 	}
 }
 
+func TestNewPodIdentityCredentialProviderTimeout(t *testing.T) {
+	oneHundredMs := 100 * time.Millisecond
+	oneSec := 1 * time.Second
+	fiftyMs := 50 * time.Millisecond
+	fiveSecs := 5 * time.Second
+
+	tests := []struct {
+		name                   string
+		podIdentityHttpTimeout *time.Duration
+		expectError            bool
+	}{
+		{
+			name:                   "100ms timeout",
+			podIdentityHttpTimeout: &oneHundredMs,
+			expectError:            false,
+		},
+		{
+			name:                   "1s timeout",
+			podIdentityHttpTimeout: &oneSec,
+			expectError:            false,
+		},
+		{
+			name:                   "50ms timeout",
+			podIdentityHttpTimeout: &fiftyMs,
+			expectError:            false,
+		},
+		{
+			name:                   "5s timeout",
+			podIdentityHttpTimeout: &fiveSecs,
+			expectError:            false,
+		},
+		{
+			name:                   "nil timeout",
+			podIdentityHttpTimeout: nil,
+			expectError:            false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			k8sClient := fake.NewSimpleClientset().CoreV1()
+
+			provider, err := NewPodIdentityCredentialProvider(
+				testRegion, testNamespace, testServiceAccount, testPodName, "", tt.podIdentityHttpTimeout, k8sClient)
+
+			if tt.expectError && err == nil {
+				t.Errorf("Expected error but got none")
+			}
+			if !tt.expectError && err != nil {
+				t.Errorf("Unexpected error: %v", err)
+			}
+
+			if !tt.expectError && provider != nil {
+				// Verify the timeout is set correctly by checking the HTTP client
+				podProvider, ok := provider.(*PodIdentityCredentialProvider)
+				if !ok {
+					t.Error("Expected PodIdentityCredentialProvider type")
+				} else if tt.podIdentityHttpTimeout != nil && podProvider.httpClient.GetTimeout() != *tt.podIdentityHttpTimeout {
+					t.Errorf("Expected HTTP client timeout %v, got %v", tt.podIdentityHttpTimeout, podProvider.httpClient.GetTimeout())
+				}
+			}
+		})
+	}
+}
+
 func TestNewPodIdentityCredentialProviderValidation(t *testing.T) {
 	tests := []struct {
 		name                string
@@ -388,7 +455,7 @@ func TestNewPodIdentityCredentialProviderValidation(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			provider, err := NewPodIdentityCredentialProvider(
-				tt.region, testNamespace, testServiceAccount, testPodName, "", tt.k8sClient)
+				tt.region, testNamespace, testServiceAccount, testPodName, "", nil, tt.k8sClient)
 
 			if tt.expectedErrorPrefix == "" {
 				if err != nil {
diff --git a/main_test.go b/main_test.go
new file mode 100644
index 0000000..669fd71
--- /dev/null
+++ b/main_test.go
@@ -0,0 +1,141 @@
+package main
+
+import (
+	"flag"
+	"os"
+	"testing"
+	"time"
+)
+
+func TestParsePodIdentityHttpTimeout(t *testing.T) {
+	oneHundredMs := 100 * time.Millisecond
+	twoSecs := 2 * time.Second
+	fiveHundredMs := 500 * time.Millisecond
+	thirtyFiveSecs := 35 * time.Second
+	thirtySecs := 30 * time.Second
+	thirtyPoint001Milliseconds := 30001 * time.Millisecond
+
+	tests := []struct {
+		name           string
+		timeoutValue   string
+		expectedResult *time.Duration
+	}{
+		{
+			name:           "valid timeout - 100ms",
+			timeoutValue:   "100ms",
+			expectedResult: &oneHundredMs,
+		},
+		{
+			name:           "valid timeout - 2s",
+			timeoutValue:   "2s",
+			expectedResult: &twoSecs,
+		},
+		{
+			name:           "valid timeout - 500ms",
+			timeoutValue:   "500ms",
+			expectedResult: &fiveHundredMs,
+		},
+		{
+			name:           "high timeout - 35s (should warn but return value)",
+			timeoutValue:   "35s",
+			expectedResult: &thirtyFiveSecs,
+		},
+		{
+			name:           "invalid timeout format (should return default)",
+			timeoutValue:   "invalid",
+			expectedResult: nil,
+		},
+		{
+			name:           "zero timeout (should return nil)",
+			timeoutValue:   "0s",
+			expectedResult: nil,
+		},
+		{
+			name:           "negative timeout (should return nil)",
+			timeoutValue:   "-100ms",
+			expectedResult: nil,
+		},
+		{
+			name:           "empty timeout (should use nil)",
+			timeoutValue:   "",
+			expectedResult: nil,
+		},
+		{
+			name:           "exactly 30s (should not warn)",
+			timeoutValue:   "30s",
+			expectedResult: &thirtySecs,
+		},
+		{
+			name:           "just over 30s (should warn but return value)",
+			timeoutValue:   "30001ms",
+			expectedResult: &thirtyPoint001Milliseconds,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result := parsePodIdentityHttpTimeout(tt.timeoutValue)
+
+			if result == nil && tt.expectedResult == nil {
+				return
+			}
+
+			if result == nil || tt.expectedResult == nil {
+				t.Errorf("Expected timeout %v, got %v", tt.expectedResult, result)
+			}
+
+			if *result != *tt.expectedResult {
+				t.Errorf("Expected timeout %v, got %v", tt.expectedResult, result)
+			}
+		})
+	}
+}
+
+// Test the flag parsing behavior
+func TestFlagParsing(t *testing.T) {
+	// Save original args
+	oldArgs := os.Args
+	defer func() { os.Args = oldArgs }()
+
+	tests := []struct {
+		name         string
+		args         []string
+		expectedFlag string
+	}{
+		{
+			name:         "default timeout",
+			args:         []string{"cmd"},
+			expectedFlag: "100ms",
+		},
+		{
+			name:         "custom timeout",
+			args:         []string{"cmd", "--pod-identity-http-timeout=250ms"},
+			expectedFlag: "250ms",
+		},
+		{
+			name:         "custom timeout with equals",
+			args:         []string{"cmd", "--pod-identity-http-timeout=2s"},
+			expectedFlag: "2s",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			// Reset flags for each test
+			flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
+
+			// Re-declare the flag (simulating what's in main.go)
+			testPodIdentityHttpTimeout := flag.String("pod-identity-http-timeout", "100ms", "The HTTP timeout threshold for Pod Identity authentication.")
+
+			// Set test args
+			os.Args = tt.args
+
+			// Parse flags
+			flag.Parse()
+
+			if *testPodIdentityHttpTimeout != tt.expectedFlag {
+				t.Errorf("Expected flag value %s, got %s", tt.expectedFlag, *testPodIdentityHttpTimeout)
+			}
+		})
+	}
+}
diff --git a/server/server_test.go b/server/server_test.go
index 99c2f1d..97b252e 100644
--- a/server/server_test.go
+++ b/server/server_test.go
@@ -10,6 +10,7 @@ import (
 	"strconv"
 	"strings"
 	"testing"
+	"time"
 
 	"github.com/aws/aws-sdk-go-v2/aws"
 	"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
@@ -97,7 +98,7 @@ func (m *MockSecretsManagerClient) DescribeSecret(ctx context.Context, input *se
 	return rsp, nil
 }
 
-func newServerWithMocks(tstData *testCase, driverWrites bool) *CSIDriverProviderServer {
+func newServerWithMocks(tstData *testCase, driverWrites bool, podIdentityHttpTimeout *time.Duration) *CSIDriverProviderServer {
 
 	var ssmRsp, backupRegionSsmRsp []*ssm.GetParametersOutput
 	var gsvRsp, backupRegionGsvRsp []*secretsmanager.GetSecretValueOutput
@@ -203,9 +204,10 @@ func newServerWithMocks(tstData *testCase, driverWrites bool) *CSIDriverProvider
 	clientset := fake.NewSimpleClientset(sa, pod, node)
 
 	return &CSIDriverProviderServer{
-		secretProviderFactory: factory,
-		k8sClient:             clientset.CoreV1(),
-		driverWriteSecrets:    driverWrites,
+		secretProviderFactory:  factory,
+		k8sClient:              clientset.CoreV1(),
+		driverWriteSecrets:     driverWrites,
+		podIdentityHttpTimeout: podIdentityHttpTimeout,
 	}
 
 }
@@ -2210,7 +2212,7 @@ func TestMounts(t *testing.T) {
 		t.Run(tst.testName, func(t *testing.T) {
 
 			dir := t.TempDir() // t.TempDir() handles cleanup automatically
-			svr := newServerWithMocks(&tst, false)
+			svr := newServerWithMocks(&tst, false, nil)
 
 			// Do the mount
 			req := buildMountReq(t, dir, tst, []*v1alpha1.ObjectVersion{})
@@ -2247,7 +2249,7 @@ func TestMountsNoWrite(t *testing.T) {
 
 			dir := t.TempDir() // t.TempDir() handles cleanup automatically
 
-			svr := newServerWithMocks(&tst, true)
+			svr := newServerWithMocks(&tst, true, nil)
 
 			// Do the mount
 			req := buildMountReq(t, dir, tst, []*v1alpha1.ObjectVersion{})
@@ -2666,7 +2668,7 @@ func TestReMounts(t *testing.T) {
 
 		t.Run(tst.testName, func(t *testing.T) {
 
-			svr := newServerWithMocks(&tst, false)
+			svr := newServerWithMocks(&tst, false, nil)
 
 			// Do the mount
 			req := buildMountReq(t, dir, tst, curState)
@@ -2704,7 +2706,7 @@ func TestNoWriteReMounts(t *testing.T) {
 
 		t.Run(tst.testName, func(t *testing.T) {
 
-			svr := newServerWithMocks(&tst, true)
+			svr := newServerWithMocks(&tst, true, nil)
 
 			// Do the mount
 			req := buildMountReq(t, dir, tst, curState)
@@ -2738,7 +2740,7 @@ func TestNoWriteReMounts(t *testing.T) {
 
 func TestEmptyAttributes(t *testing.T) {
 
-	svr := newServerWithMocks(nil, false)
+	svr := newServerWithMocks(nil, false, nil)
 	req := &v1alpha1.MountRequest{
 		Attributes:           "", // Should error
 		TargetPath:           "/tmp",
@@ -2759,7 +2761,7 @@ func TestEmptyAttributes(t *testing.T) {
 
 func TestNoPath(t *testing.T) {
 
-	svr := newServerWithMocks(nil, false)
+	svr := newServerWithMocks(nil, false, nil)
 	req := &v1alpha1.MountRequest{ // Missing TargetPath
 		Attributes:           "{}",
 		Permission:           "420",
@@ -2789,7 +2791,7 @@ func TestGetRegionFromNodeWithAWSRegionEnvVar(t *testing.T) {
 			"podName":   "fakePod",
 			"nodeName":  "fakeNode",
 		},
-	}, false)
+	}, false, nil)
 
 	region, err := svr.getRegionFromNode(context.TODO(), "fakeNS", "fakePod")
 
@@ -2812,7 +2814,7 @@ func TestGetRegionFromNodeWithNodeLabels(t *testing.T) {
 			"podName":   "fakePod",
 			"nodeName":  "fakeNode",
 		},
-	}, false)
+	}, false, nil)
 
 	region, err := svr.getRegionFromNode(context.TODO(), "fakeNS", "fakePod")
 	if err != nil {
@@ -2834,7 +2836,7 @@ func TestGetRegionFromNodeError(t *testing.T) {
 			"podName":   "fakePod",
 			"nodeName":  "FailNode",
 		},
-	}, false)
+	}, false, nil)
 
 	_, err := svr.getRegionFromNode(context.TODO(), "fakeNS", "fakePod")
 	if err == nil {
@@ -2844,8 +2846,7 @@ func TestGetRegionFromNodeError(t *testing.T) {
 
 // Make sure the Version call works
 func TestDriverVersion(t *testing.T) {
-
-	svr, err := NewServer(nil, nil, true)
+	svr, err := NewServer(nil, nil, true, nil)
 	if err != nil {
 		t.Fatalf("TestDriverVersion: got unexpected server error %s", err.Error())
 	}