How Acceldata Extended Apache Ranger Governance to Amazon S3
The Apache Ranger project has tracked open requests for S3 support, ticketed as RANGER 1300, since June 2018, and it remains Open and Unresolved today and continued patch attempts as recently as November 2024. Two prior efforts had already tried to close this gap. Amazon Web Services built the EMRFS S3 plugin for its own EMR product line, which restores inline enforcement but works only on Amazon EMR, and a separate open source project maintained by ING Bank lets administrators author Ranger policies for S3 compatible storage such as Ceph but stops short of actually pushing and enforcing them.
Acceldata addresses this gap through a Ranger S3 plugin built on top of Apache Ranger 2.5.0, presented as a sample solution to RANGER 1300 rather than an upstream merge.
Rather than restoring inline enforcement, the plugin turns Ranger Admin into a policy compiler: administrators author policy in Ranger's native vocabulary, and a translation engine converts that policy into a native AWS S3 bucket policy document, pushed directly to the bucket through the AWS SDK. Enforcement then runs entirely inside AWS, at full native speed, targeting real AWS S3 rather than only S3 compatible stores. The implementation goes further than prior attempts by adding two sided change detection to avoid redundant API calls, ARN snapshotting to clean up stale statements on policy deletion or path changes, and explicit coexistence handling so hand authored IAM statements already on a bucket are preserved rather than overwritten.
Problem Statement
Apache Ranger provides a centralized authorization and audit control plane for the on-premise Hadoop ecosystem. It covers HDFS, Hive, HBase, Kafka, Knox, Ozone, and several other services through a single policy management interface. As organizations move data lakes onto Amazon S3, this control plane does not extend automatically. S3 access is governed by AWS IAM, which is a separate system that Ranger does not manage and does not observe. This document walks through how the Ranger S3 plugin closes that gap, based on the implementation built on top of Apache Ranger 2.5.0, and how you can reason about applying the same pattern in your own environment.
How Classic Ranger Plugins Work
Ranger classically operates as two cooperating components. The Ranger Admin server is the central authority. It runs the policy management UI, exposes RESTful CRUD APIs, stores policies in a relational database, and synchronizes users and groups from LDAP or Active Directory. The second component is the service plugin, a lightweight agent embedded directly inside each protected service, such as the HDFS NameNode, HiveServer2, or an HBase RegionServer.
Each embedded plugin follows the same lifecycle. It periodically downloads policies from Ranger Admin and caches them locally for performance. When a request arrives, the plugin intercepts it before the service processes it, evaluates it against the cached policy set, and either allows or denies the request on the spot. An audit event is then streamed to a centralized audit store. The defining property of this model is that the decision point and the enforcement point sit in the same process. This is only possible because Ranger controls the code path of the service it protects.
Why this Model Does Not Extend to S3
Amazon owns and operates the S3 request handling code path in full. There is no service process inside S3 where a Ranger agent can be embedded, so inline interception is not an available option. A team could place a proxy or gateway in front of S3 to recreate that interception point artificially, but this introduces network latency on every request, adds a single point of failure, and increases bandwidth cost. In practice, this trade off is rarely acceptable for production data pipelines.
A second and more immediate problem is that most access to S3 does not go through any intermediary at all. Direct AWS SDK calls, AWS CLI commands, and connectors such as s3a:// all reach S3 using IAM credentials, and none of these paths pass through Ranger. This produces three concrete limitations. There is no centralized audit trail for S3 access, because Ranger sits outside the request path entirely. The same data is governed inconsistently depending on how it is reached, since IAM and Ranger apply their rules independently rather than in coordination. Compliance reporting becomes difficult, because no single system can state with certainty who accessed which object. On top of this, permission changes typically require coordination between a DevOps or cloud team that owns IAM and a data platform team that owns Ranger, which adds operational latency to routine access requests.
The Policy Push Model
The Ranger S3 plugin addresses this by changing what Ranger's role is for cloud storage, rather than trying to force the classic inline model into an environment where it cannot function. Ranger Admin becomes a policy compiler and synchronizer. Administrators continue to author policy using the same Ranger vocabulary they already use for HDFS or Hive. The plugin then translates that policy into a native AWS S3 bucket policy document and installs it on the bucket through the AWS SDK. From that point forward, AWS itself performs enforcement natively, on every access path, regardless of whether the request originates from the AWS CLI, an SDK call, the s3a:// connector, or the AWS console.
The distinction between the two models can be summarized directly.
| Aspect | Classic Ranger plugin, for example HDFS | Ranger S3 plugin |
|---|---|---|
| Decision point | Ranger policy engine, embedded in the service | AWS S3 itself, natively |
| Enforcement point | The data service, such as the NameNode | AWS S3 itself, natively |
| What Ranger ships | Policies pulled by an agent and evaluated per request | Compiled bucket policies pushed once per policy change |
| Where it runs | A long running agent inside the data service | Ranger Admin, triggered on policy CRUD operations |
| Runtime dependency | The agent must be running for authorization to occur | None, since AWS continues to enforce even if Ranger Admin is offline |
| Audit | Ranger audit store | Not provided by the plugin, see the limitations section |
Because AWS performs enforcement independently of Ranger's availability, a Ranger Admin outage does not remove access control from the bucket. It only prevents new policy changes from being compiled and pushed until the server is restored. This is a meaningful operational property for any team evaluating the model.
System Architecture
The architecture connects three domains: the Ranger Admin server where policy is authored, the AWS IAM service where principals are resolved, and the AWS S3 bucket policy where enforcement ultimately happens. Hadoop ecosystem tools such as Hive and Spark continue to reach S3 through the standard s3a:// connector, and this connector is never modified. It simply hits a bucket whose policy is now kept in sync by Ranger.

This diagram makes the separation explicit. The top path, from the Ranger Admin UI through the translation engine to AWS IAM and the S3 bucket policy, runs only when an administrator creates, updates, or deletes a policy. The bottom path, where HDFS and Hive or Spark reach S3 through s3a://, runs on every single data access and never touches Ranger at all. The two paths meet only at the bucket policy itself, which is the artifact the top path produces and the artifact AWS consults on every request in the bottom path.
The Resource and Policy Model
Ranger models S3 as a single hierarchical path resource that represents both buckets and objects, matched with wildcard and recursive support enabled. Administrators express two distinct kinds of policy.
- A bucket level policy uses a resource such as bucket1/ and grants the s3:ListBucket action, which allows listing objects in the bucket.
- An object level policy uses a resource such as
bucket1/*orbucket1/prefix/*and grantss3:GetObject,s3:PutObject, ors3:DeleteObject, which govern reading, writing, and deleting individual objects.
These two policy kinds must be authored separately, because they translate into different ARN shapes in AWS: arn:aws:s3:::bucket1 for the bucket itself, versus arn:aws:s3:::bucket1/* for objects inside it.
The service definition intentionally exposes exactly four access types: s3:ListBucket, s3:GetObject, s3:PutObject, and s3:DeleteObject. These names are chosen to match AWS action names exactly, so translation into the IAM action array becomes a direct pass through rather than a lookup table. Consider a policy that grants two developers read access to every object in bucket1.
Policy Name: allow-dev-bucket1-objects-read
Users: [dev-user1, dev-user2]
Resource: bucket1/*
Actions: [GetObject], Allow
The translation engine compiles this into the following S3 bucket policy statement, which AWS installs and enforces directly.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::111112222222:user/dev-user1",
"arn:aws:iam::111112222223:user/dev-user2"
]
},
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::bucket1/*"
}
]
}
Four mapping rules govern every translation of this kind. Ranger users and roles resolve to full IAM ARNs, and this requires an exact name match between the Ranger identity and the IAM identity. A resource path such as bucket1/* maps directly to the corresponding S3 ARN. An access type such as GetObject passes through unchanged into the corresponding s3:GetObject action. Finally, an allow item in Ranger produces an Allow effect, and a deny item produces a Deny effect, so explicit denies in Ranger surface as explicit denies in the AWS bucket policy.
Inside the Translation Engine
All translation logic runs on the Ranger Admin server inside ServiceDBStore, and the entry point is createS3BucketPolicy, invoked from ServiceREST on every S3 policy create, update, or delete operation. Understanding its internal sequence matters if you plan to operate this system at scale, since it determines how frequently AWS APIs get called and how safely concurrent edits behave.
The engine begins by loading the S3 service configuration and constructing an S3Client and an IamClient from the AWS SDK. It then computes which buckets are affected by the change and builds a search filter so that, for a single non wildcard bucket, only the relevant policies are fetched rather than the entire service policy set. Before doing any further work, it performs change detection: it compares the incoming policy against the version stored in the database, checking both policy items and resources. If nothing has actually changed, the engine returns immediately without making any AWS call. This matters in production because it prevents unnecessary PutBucketPolicy calls from accumulating against AWS API rate limits during routine administrative activity.
If the policy is genuinely new or altered, the engine snapshots the old resource ARNs from the previous version of the policy before recompiling anything. This step exists specifically to handle two cases. When a policy's resource path changes, for example from bucketA/* to bucketB/*, the statement previously installed under the old ARN must be removed rather than left behind as an orphan. When a policy is deleted outright, the same cleanup applies. These snapshot ARNs are later treated as Ranger managed, which allows the merge step to drop any stale statement safely.
The engine then combines the effective policy set for the affected buckets, groups policies by bucket, and for each bucket builds a list of policy statements. Object and bucket paths are prefixed into full ARNs, and one statement is emitted per resource and policy item pairing, kept separate for allow items and deny items. Principal resolution happens through addAccounts, which calls IamClient.getUser for users and IamClient.getRole for roles, parses the account ID from the returned ARN, and reconstructs a canonical principal ARN. An in memory cache keyed by entity type and entity name avoids redundant IAM lookups within a single synchronization run. One deliberate limitation surfaces here: group principals are explicitly not supported, because AWS resource based bucket policies cannot reference IAM groups as principals at all. A group item in a Ranger policy is logged and skipped rather than silently dropped, which is worth watching for in your own audit logging if you rely on group based policies today.
Once every statement is built, the engine wraps the result in an S3BucketPolicy object with Version set to 2012-10-17 and serializes it to JSON. Before pushing anything, updateBucketPolicyIfChanged reads the current bucket policy from AWS through GetBucketPolicy, compares it structurally against the freshly compiled policy, and calls PutBucketPolicy only if the two differ. This is the second of two independent no op checks in the pipeline, one on the Ranger side comparing against the database and one on the AWS side comparing against the live policy, and together they keep the plugin idempotent under repeated or redundant updates.
End to End Lifecycle of a Policy Change
The full sequence, from an administrator's action in the UI to enforcement on the bucket, can be traced as a single flow.

This sequence also explains a deployment detail that is easy to miss. Because bucket level and object level policies compile into separate statements with different ARN shapes, deletion order matters operationally. Object level policies should be removed before the corresponding bucket level policy. Deleting the bucket level policy removes the associated object level statements from IAM automatically, but those object level policies can continue to appear in the Ranger UI even though they no longer exist in IAM, which can be confusing during an audit unless the team is aware of this behavior in advance.
Note that, Merge statements only apply delta to Ranger set policies, while preserving statements/policies preset in IAM.
Coexistence with Existing IAM Statements
Production buckets rarely start with an empty policy. They typically already carry hand authored IAM statements written before Ranger was introduced. The engine handles this through mergeWithIAMStatements and extractIAMOnlyStatements. It reads the existing bucket policy from AWS and partitions its statements into two sets. A statement is classified as Ranger managed if its resource ARN falls within the union of the old snapshot ARNs and the new ARNs computed for the current synchronization. Every other statement is classified as IAM only and is preserved unchanged, placed first in the merged document. The freshly compiled Ranger statements are appended after that, and the combined result is serialized and conditionally pushed as described earlier.
This design makes Ranger authoritative only for the specific resources it manages. It is important to understand the boundary of this guarantee precisely. For any resource that Ranger does manage, Ranger becomes the source of truth and will overwrite the corresponding resource based statement on every synchronization, replacing whatever was there before with the current compiled output. Teams evaluating this plugin should review existing bucket permissions carefully before enabling pushdown, since an existing statement covering a Ranger managed resource will be replaced rather than merged.
Deployment Prerequisites
Setting this up in your own environment requires a small set of concrete steps. You need at least one dedicated S3 bucket for the teams managing the Hadoop cluster, and a Hadoop cluster admin IAM identity whose access key and secret key are used to configure the Ranger S3 service. This identity requires permission to read IAM metadata and to manage the target bucket's policy. Individual users of the Hadoop and operations teams also need sub user IAM identities with limited permissions, since these are the principals that Ranger policies will ultimately grant or deny access to.
Ranger Admin must also trust the certificate chain presented by the S3 and IAM endpoints, since all communication happens over TLS. This is typically done by fetching the endpoint certificate and importing it into the Ranger truststore.
echo | openssl s_client -connect s3.ap-south-1.amazonaws.com:443 -showcerts 2>&1 | \
awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{ if(/BEGIN/){a++}; out="cert"a".pem"; print > out }'
keytool -importcert -alias aws-cert -file cert.pem \
-keystore /etc/security/certificates/truststore.jks
The corresponding Ranger Admin configuration then needs to point at that truststore, for example through ranger.truststore.alias, ranger.truststore.file, and ranger.truststore.password. A missing or misconfigured truststore surfaces immediately as an SdkClientException: No X509TrustManager implementation available when running the connection test, which is a useful diagnostic signal if provisioning fails.
Provisioning itself follows a short sequence. Configure TLS and restart Ranger Admin. Synchronize or manually create Ranger users whose names match the corresponding IAM usernames exactly, since name matching is required for principal resolution. Create the S3 service through the Ranger UI's Service Manager, supplying the access key, secret key, endpoint URL, region, and bucket name. Run the connection test, which internally calls ListObjectsV2 against the bucket to confirm connectivity. On service creation, a default policy is generated automatically, granting the configured lookup user s3:ListBucket on the bucket, and administrators can begin authoring further policies from that point.
Validation Results
The plugin has been validated against representative workloads across three access paths. For HDFS accessed through S3A, granting ListBucket alone permits directory listing but blocks writes with a 403 response. Adding GetObject, PutObject, and DeleteObject enables both single object and recursive put and delete operations, and applying an explicit deny on PutObject or DeleteObject causes AWS to return an explicit deny response from the resource based policy, which confirms that Ranger's deny intent is honored natively by AWS rather than merely by Ranger's own logic. For Hive over S3A, external tables behave according to policy in the expected way: SELECT requires GetObject, INSERT requires PutObject, and staging cleanup requires DeleteObject, with insufficient permissions failing as a standard S3 403 AccessDenied error. For Spark over S3A, a six case permission suite covering list, put, get, overwrite, partitioned write, and delete operations passed end to end whenever the corresponding Ranger policy was in place.
Limitations to Account for Before Adopting This Pattern
Several constraints follow directly from the policy push model and from AWS's own resource based policy semantics, and any team planning to replicate this architecture should account for them upfront.
There is no plugin provided audit trail for individual S3 operations, since enforcement happens natively inside AWS and Ranger never observes the request path; teams that need this visibility should rely on AWS native mechanisms such as CloudTrail or S3 access logs instead. Ranger usernames must match IAM usernames exactly, and any users synchronized from AD or LDAP are assumed to already exist in IAM under the same name.
Groups are not supported as principals, because AWS resource based policies cannot reference IAM groups directly, so group items present in a Ranger policy are skipped during translation.
Only four actions are currently supported: list, get, put, and delete. The plugin cannot create buckets from Ranger, and it does not enforce on temporary credentials issued through AWS STS.
There is no reverse pushdown capability, meaning Ranger does not import pre existing S3 ACLs or bucket policies.
Finally, as already noted, Ranger overwrites the resource based statements for any resource it manages, so a careful review of existing bucket permissions is a required step before enabling this integration in any environment that already has hand authored policies.
Next Steps
The S3 plugin is presented as one member of a broader Ranger cloud integration effort applying the same policy push pattern to other object stores. Planned work extends the same translation model to Google Cloud Storage bucket IAM bindings and to Azure Blob Storage ACLs, giving a hybrid environment a single authorization plane across all three major cloud providers rather than one plugin built in isolation. Additional planned work includes bridging Ranger groups into AWS through identity based policies or an explicit group expansion strategy, since resource based policies fundamentally cannot reference IAM groups today, along with broader action coverage beyond the current four S3 actions, and a reverse pushdown capability that would let teams import existing cloud policies into Ranger rather than starting from a clean slate.
Summary for Teams Evaluating this Architecture
The core idea to take away from this design is straightforward. Rather than trying to recreate inline interception where none is technically possible, the plugin turns Ranger Admin into a compiler that lowers Ranger policy intent into a cloud provider's native enforcement mechanism, and it runs only at policy edit time rather than on every request. This removes any added latency from the S3 data path entirely, keeps a single authoring surface for both on premises and cloud resources, and continues to enforce access even during a Ranger Admin outage. The trade offs are equally concrete: there is no native audit trail inside Ranger for S3 operations, group principals are not supported, and Ranger becomes the unconditional source of truth for any resource it manages. Any team replicating this pattern for GCS, Azure, or another provider should design around these same constraints from the start, rather than discovering them after the integration is already in production.
For more implementation notes on Ranger, cloud governance, and the broader engineering work behind Acceldata's data platform, visit engineering.acceldata.io, where the team regularly publishes deeper technical writeups on how large scale data systems like this one get built and operated.