Transfer Family SFTP Login Works but S3 Access Fails: Trace the Denied Operation
Trace a Transfer Family SFTP list or read denial through logical mappings, the actual role and session, S3 resources and KMS evidence before proposing a change.
Primary sources checked
Start with the failed operation, not the successful login
An accepted SFTP login does not establish permission to list an S3 prefix or read an object. Start with the failed client operation and its virtual path. Resolve that path through the user's actual logical-directory mapping, identify the assigned role and session policy, then collect the applicable S3 and, where relevant, KMS evidence. The useful output is a denial trace with a named owner and next action, not a larger policy copied from an example.
This guide is for an operator investigating an existing AWS Transfer Family SFTP server with confirmed HomeDirectoryType=LOGICAL and confirmed direct S3 general-purpose-bucket targets. It covers accepted authentication followed by a directory-listing or file-read denial. It does not cover EFS, S3 directory buckets, AS2, server creation, uploads or identity-provider repairs. It authorizes no permission changes, payload reads or live reproductions. Begin with existing configuration and previously collected, authorized evidence. A separate change or test approval is needed to go further.
The three worked records are synthetic, all stipulating confirmed LOGICAL homes and direct general-purpose-bucket targets. Their names, paths, policy summaries and observations are invented teaching inputs, not customer evidence or AWS test results. You can use the same record structure with approved metadata from your environment. Keep secrets, private filenames and file contents out of the shared incident note.
Separate logical-path enforcement from storage authority
Logical directories provide a virtual namespace. A visible entry such as /inbox can map to an S3 target such as /example-bucket/partners/alpha/inbound. Transfer Family also enforces logical traversal boundaries and validates relative paths before sending requests to S3. This is a real service control, not merely a cosmetic rename. It still does not grant the associated role permission to access the mapped storage. AWS logical-directory behavior.
Before resolving a target, have its configuration owner confirm the home-directory type and target kind from existing approved records. If it is PATH, an access-point alias or unknown, stop this procedure and hand the exact configuration to that owner for a separately scoped review. A PATH home without logical mappings is not itself a configuration fault. AWS permits access-point aliases in place of bucket names, with an additional policy boundary. Do not interpret an unclassified target's first component as a bucket.
For a confirmed LOGICAL/direct-bucket target, record the effective mapping returned for the affected user, not a screenshot of another user's home. Service-managed users and custom identity providers can supply that configuration differently. Capture the server and user aliases, configuration revision, logical entry, complete target and the virtual path used by the client. Resolve variables from the actual user context. Preserve spelling and case while redacting identifying labels consistently.
For example, /inbox/report.csv under the synthetic mapping above resolves to bucket example-bucket and key partners/alpha/inbound/report.csv. The bucket is not part of the object key. That distinction matters when someone compares an object ARN with a bucket-level prefix condition. A policy scoped to partners/alpha/archive/ does not describe the same target simply because both paths belong to Alpha.
If the mapping is missing, ambiguous or from a different revision, stop the policy diagnosis there. Ask the Transfer configuration owner to supply the applicable snapshot. Do not infer a target from the path shown by the SFTP client, replace a mapping or create a folder to make an error disappear. The original denied path remains the reference for the investigation.
Distinguish listing, metadata checks and object reads
Keep the client action beside the storage operation. A directory listing and a file download have different resource questions. The S3 permissions table maps ListObjectsV2 to bucket-level s3:ListBucket; an ordinary current-object read uses s3:GetObject on an object resource. An explicitly selected object version has a different permission context. This guide does not turn a version-specific request into an ordinary read. S3 operation and permission mapping.
| Observed client action | Storage evidence to seek | What success would not establish |
|---|---|---|
| List a logical directory | Resolved bucket and prefix; any recorded S3 list or metadata operation | Permission to download every listed object |
| Read a named file | Resolved object key; recorded object operation and applicable encryption context | Permission to list its parent directory |
| Browse a directory containing folder markers | Existing directory-optimization setting and any recorded HeadObject calls | That listing is always one bucket-only authorization decision |
Transfer's documented folder-marker behavior is important here. Directory listing can involve HeadObject calls for zero-byte folder objects, which require object-read permission. The optimized-directory setting changes that behavior. Record the existing setting and relevant evidence rather than enabling it, deleting markers or adding read access as an incident shortcut. A failing ls is not automatically a missing ListBucket allow. Transfer S3 listing and metadata behavior.
Write down whether the failed backend operation is observed or still unknown. A client message alone may not expose every service request. A successful direct S3 command from an administrator's laptop is also a different caller and session; it cannot substitute for this Transfer user's path. Preserve it as a separately labelled comparator only if it already exists and was authorized.
Collect the real role and stored session policy
Ask the Transfer owner for the assigned role ARN and the session-policy JSON actually associated with this user or supplied by the identity provider for the affected session. Ask for the relevant configuration revision and observation time. A role name in an onboarding document is weaker evidence than the configuration that applied to the incident. Do not collect credentials, private keys or authentication secrets.
Compare bucket-level actions against bucket resources and object actions against object resources. Review prefix conditions against the resolved target, including any expected delimiter or path conventions. A broad role permission is not enough if an applicable session policy narrows the permitted use. Neither a role-policy screenshot nor the presence of the word GetObject establishes the whole authorization result. Transfer role and storage permissions.
Transfer session policies have specific substitution rules. For a LOGICAL home-directory type, transfer:HomeBucket, transfer:HomeDirectory and transfer:HomeFolder are not supported. Do not confuse these with every available Transfer variable or assume that ${aws:Username} is the SFTP username. Transfer also stores session-policy JSON rather than a live reference to an IAM managed policy. Changing a managed policy elsewhere does not update a stored user-policy copy. Transfer session-policy rules.
Record an unsupported variable as a configuration issue for the Transfer owner to review. Do not guess its runtime expansion or claim that a particular error proves how it was evaluated. For a custom identity provider, distinguish a saved response from the response applicable to the affected login. If that response is unavailable, mark the session boundary unknown and request the smallest approved metadata export that resolves it.
Review S3 and key evidence without broadening the request
The bucket owner should review the relevant bucket policy, resource ownership configuration and applicable conditions against the actual principal, action and target. Depending on the environment, identity policies, session restrictions, permissions boundaries, organization controls, endpoint policies and explicit denies can affect access. Do not reduce the investigation to finding one allow or treat the absence of an enhanced denial explanation as evidence that a policy layer was irrelevant. AWS limits where enhanced S3 denial context is available, and one explanation need not enumerate every failing policy type. S3 denial investigation.
Use existing authorized metadata to determine whether the affected object is SSE-KMS encrypted and which key identity applies. Listing a bucket does not establish the encryption or key authorization of one object. A missing metadata record remains unknown. Do not fetch the payload or send a new HeadObject request merely to fill the worksheet without authority for that operation. Even metadata access is a separate request.
For encrypted reads, the S3 permissions table identifies a conditional kms:Decrypt requirement. Broader GetObject API wording also names kms:GenerateDataKey. That difference does not establish which additional actions this Transfer session needs. Do not assume that Transfer enables a particular checksum mode or that a directory-bucket checksum rule applies to a general-purpose bucket. If a proposed fix depends on an additional KMS action, have the key owner review the actual denied operation and request context instead of expanding access from a sample. GetObject permissions wording.
The key owner must evaluate authorization for the actual principal and key, not just confirm that a policy contains an action name. Key policies, IAM delegation and grants have their own evaluation rules. For cross-account use, permission in the key owner's account and delegation in the caller's account both matter; an S3 bucket-policy allow is not a KMS grant. Do not apply a cross-account recipe unchanged to every same-account key. KMS key-policy evaluation, cross-account KMS access.
Worked example: listing targets a different prefix
This is a synthetic, offline example. The incident alias is TF-LIST-01. The saved client record says authentication was accepted, followed by a denied listing of /inbox. The saved logical entry /inbox targets /example-bucket/partners/alpha/inbound. The configuration owner supplies matching user and revision aliases. The backend operation is not recorded.
The supplied role-policy excerpt permits s3:ListBucket on the bucket only with the prefix condition partners/alpha/archive/*. The stored session-policy excerpt names the same archive scope. These are teaching inputs, not complete effective-policy exports. The observed mapping target uses inbound, while both supplied permission excerpts describe archive. That mismatch is concrete; a bare “S3 permission problem” is not an adequate handoff.
The record's disposition is target-to-policy mismatch requiring owner review. It does not claim that the mismatch is the only cause, that the exact list request used a particular prefix string or that metadata checks could not also fail. Folder-marker and optimization evidence remain unknown. The owner should not add the whole bucket to settle those uncertainties.
The named next owner is the Transfer configuration owner, working with the bucket-policy owner. The next action is to confirm which target the approved partner exchange should use, then compare that target with the actual applicable prefix conditions and request evidence. If the intended location is archive, the mapping may be the wrong artifact; if it is inbound, the permission proposal needs its own review. The diagnostic record does not choose a repair on behalf of either owner.
Worked record 2: a role allow is absent from the user policy
This synthetic record is TF-READ-02. A previously saved listing of /inbox succeeded, and a subsequent read of /inbox/report.csv was denied. The mapping resolves the file to example-bucket/partners/bravo/inbound/report.csv. The supplied metadata says the teaching object is not SSE-KMS encrypted. No live read, listing or metadata request was performed for this example.
The assigned role's supplied policy includes s3:GetObject for that object scope. The actual stored user session-policy JSON contains a bucket-list allow but no object-read allow. The record also contains a later managed-policy revision with object-read permission, but the Transfer owner's saved user configuration still contains the earlier JSON. That difference is the evidence worth preserving. A policy document updated elsewhere is not proof that this user's stored session policy changed.
The disposition is role/session mismatch requiring review of the applicable user-policy copy. Listing success is consistent with the supplied bucket allowance and does not establish object-read authority. This record deliberately does not pronounce a complete authorization result from selected excerpts. Bucket-policy conditions and other applicable controls still need their own review before a change is approved.
The named next owner is the Transfer user-configuration owner. The next action is to compare the stored policy revision with the intended read scope and produce a narrowly scoped change proposal if necessary. The proposal must retain the correct user identity and target. Updating the shared role again, granting wildcard object access or declaring KMS the cause would not answer the mismatch recorded here.
Worked record 3: listing works, but key authority is unknown
This synthetic record is TF-READ-03. A saved client transcript shows accepted login and successful listing, followed by a denied read of /outbox/statement.csv. The mapping resolves to example-bucket/partners/charlie/outbound/statement.csv. An existing authorized object-metadata export identifies SSE-KMS encryption under key alias K-C. The alias is only a teaching label, not an ARN or sufficient evidence of the resolved key.
The supplied role and stored session policy include the object-read scope and a KMS action entry. The bucket owner's review has not identified a bucket-policy restriction in the material supplied. However, the record lacks the key's resolved identity, owner-account relationship, applicable key-policy revision and grants. The backend denied action is also unknown. There is no observed KMS event in the exercise.
The disposition is key authorization unknown, not proven KMS denial. Neither the successful listing nor the role's KMS action entry closes that gap. The absence of a recorded KMS event does not establish that no relevant request occurred. A generic read denial is not a reason to add GenerateDataKey, change the key policy or rewrite the object's encryption.
The named next owner is the key administrator, supported by the Transfer and bucket owners. The next action is an approved metadata review identifying the actual key, caller principal, account relationship and applicable authorization evidence. If a later authorized trace identifies a denied action, attach that action and context to the review. Until then, leave the cause unknown and keep the original failure record open.
Reuse this denial-trace worksheet
Create one record per failed operation. A single incident can have a listing record and a separate read record. Give both a shared incident alias, but do not overwrite the first failure when the next command behaves differently. Every evidence reference should carry its observation time and configuration revision where available.
Request and target
- Entry gate: owner-confirmed
HomeDirectoryType=LOGICAL, target kind confirmed as a direct general-purpose bucket, and the configuration evidence. PATH, access-point or unknown targets go back to the configuration owner before bucket/key fields or example interpretations apply. - Incident and owner: incident alias, Transfer owner and resource-owner contacts.
- Observation: existing authorized evidence reference, time, accepted-login evidence, failed client action and sanitized error.
- Virtual path: exact path and whether it is a directory or named file.
- Resolved storage: logical entry, target, bucket, prefix or key, mapping revision and variable context.
- Backend operation: observed action and request reference, or explicitly unknown. Separate facts from inferred candidates.
Caller and applicable boundaries
- Assigned role: exact role identity and the configuration evidence that ties it to this user and session.
- Session policy: actual JSON or approved reference, revision, supported variables and missing evidence.
- S3 review: applicable bucket/object actions, resource scope, conditions, ownership and other relevant policy layers.
- Encryption review: existing metadata source, SSE-KMS applicability, resolved key identity and account relationship, or unknown.
- Key review: key-owner evidence, caller delegation and applicable restrictions. Do not replace this field with “KMS allowed.”
Decision and handoff
- Supported finding: concrete mismatch or observation, with the evidence that supports it.
- Not established: unresolved operation, policy context or resource identity that prevents a stronger conclusion.
- Next action: named owner, smallest required evidence or separately reviewed change proposal, and due review point.
- Closure evidence: what would show the requested operation works within the approved scope, plus what must remain denied.
Keep the worksheet in an access-controlled incident location. Share aliases in broader discussions, retaining a controlled reference to the actual resources. A summary saying “permissions checked” is not reusable: the next operator needs to know which principal, policy revision, action and path were checked.
Alternatives: choose the next investigation without turning it into a repair
Use configuration comparison first when the logical target or session-policy revision is uncertain. It is usually the smallest evidence request and does not require object access. Its limit is that a plausible configuration comparison does not reveal every backend request or establish a successful transfer.
Use existing service and audit evidence when the target is known but the failed backend operation is not. Ask the evidence owner what was enabled and retained for the incident window. CloudTrail Event history alone is not an S3 object-read audit trail. Missing data-event evidence is a coverage gap, not proof of no request. See the separate S3 GetObject evidence-gap decision when logging coverage is the unresolved question. Do not change logging as part of this read-only procedure.
Consider a separately approved synthetic reproduction only when existing evidence cannot distinguish the remaining causes. It needs an approved non-sensitive target, the intended identity and mapping, bounded requests and costs, inert downstream behavior and explicit stop conditions. Do not run a download against a real partner payload as a convenient test. An administrator's direct S3 test, even if approved, remains a comparator with a potentially different policy and network context.
Permission or mapping changes belong to the relevant change process. The denial trace should make that proposal smaller and better supported, not bypass review. The cross-account file-exchange case describes the broader platform decision; this worksheet serves the narrower failed-operation investigation.
Stop safely and hand over a testable question
Stop if the review requires unapproved account access, private payload exposure, credentials, a broader resource scope or a new operation outside the agreed evidence boundary. Also stop if a proposed reproduction can affect live downstream consumers or its request and cost bounds are not defined. Preserve the original failure and record what approval or evidence is missing. Do not retry automatically or remove a control to obtain a cleaner transcript.
Because this procedure changes no configuration or content, recovery means preserving the record and returning it to the owner, not promising a rollback. If another team already made a change, record its revision and timing separately. Never rewrite the earlier evidence to match the new configuration. A later successful read does not retrospectively explain the earlier denial.
The immediate next step is to fill Request and target for one failed operation using existing approved evidence. Send the unresolved field to its named owner before requesting a policy edit. Close the investigation only when the cause is supported, any proposed repair has its own approval, and separately authorized validation covers the intended operation and the agreed negative boundary. Until that evidence exists, use “identified mismatch” or “cause unknown,” not “fixed.”