Skip to content

Commit 8ad56ba

Browse files
authored
Merge pull request #186 from ing-bank/feature/auth-interface
Introducing authorization interface
2 parents a94a6c5 + a412591 commit 8ad56ba

File tree

18 files changed

+319
-255
lines changed

18 files changed

+319
-255
lines changed

.github/workflows/feature.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ jobs:
2020
- uses: actions/checkout@v2
2121
with:
2222
fetch-depth: '0'
23+
- name: Setup Scala
24+
uses: actions/setup-java@v3
25+
with:
26+
distribution: temurin
27+
java-version: "17"
2328
- name: Build and publish docker image
2429
run: |
2530
# Login to docker

README.md

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -176,35 +176,6 @@ debug civetweb = 20
176176

177177
2. Restart rgw process (either docker stop <ceph/daemon rgw> or whole ceph/demo)
178178

179-
# Lineage to Atlas
180-
181-
Currently it is possible to create lineage based on incoming request to proxy server. It is however disabled by
182-
default (preview feature). To enable lineage shipment to Atlas, following setting has to be added to application.conf:
183-
184-
```
185-
rokku {
186-
atlas {
187-
enabled = true
188-
}
189-
}
190-
```
191-
192-
As alternative environment value `ROKKU_ATLAS_ENABLED` should be set to true.
193-
194-
Lineage is done according to model
195-
196-
![alt text](./docs/img/atlas_model.jpg)
197-
198-
To check lineage that has been created, login to Atlas web UI console, [default url](http://localhost:21000) with
199-
admin user and password
200-
201-
## Classifications and metadata
202-
203-
You can set classifications and metadata to objects in lineage by setting http headers:
204-
205-
* **rokku-metadata** - key value pair in format _key1=val1,key2=val2_ - the matadata is presented in lineage entity as "awsTags" properties.
206-
* **rokku-classifications** - comma separated classifications names (the classifications must exist)
207-
208179
# Events Notification
209180

210181
Rokku can send event notification to message queue based on user requests, in [AWS format](https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html).
@@ -338,15 +309,26 @@ ROKKU_KERBEROS_KEYTAB: "keytab_full_path"
338309
ROKKU_KERBEROS_PRINCIPAL: "user"
339310
```
340311

341-
# Ranger Audit Log
312+
# Authorization plugin
313+
314+
By default rokku uses Apache Ranger for authorization but you can change it.
315+
To provide other implementation you need:
316+
317+
1. implement [AccessControl](./src/main/java/com/ing/wbaa/rokku/proxy/security/AccessControl.java) - example is [Ranger](./src/main/scala/com/ing/wbaa/rokku/proxy/provider/AccessControlProviderRanger.scala)
318+
2. configure
319+
* set the access control class in the config [access-control.class-name](./src/main/resources/reference.conf) or environment ```ROKKU_ACCESS_CONTROL_CLASS_NAME=...```
320+
* if you need any specific configuration for the plugin add it to [access-control.plugin-param](./src/main/resources/reference.conf)
321+
3. add the access control class to rokku classpath
322+
323+
# Authorization Audit Log
342324

343325
To enable the log set:
344326

345327
```bash
346-
ROKKU_RANGER_ENABLED_AUDIT="true"
328+
ROKKU_ENABLED_AUDIT="true"
347329
```
348330

349-
and provide on the classpath the ranger-s3-audit.xml configuration.
331+
For AccessControlProviderRanger you need to provide on the classpath the ranger-s3-audit.xml configuration.
350332

351333
# ECS multi namespace support
352334

build.sbt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ val metricVersion = "4.2.12"
2323

2424
libraryDependencies ++= Seq(
2525
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
26-
"ch.qos.logback" % "logback-classic" % "1.4.5",
26+
"ch.qos.logback" % "logback-classic" % "1.4.7",
2727
"ch.qos.logback.contrib" % "logback-json-classic" % logbackJson,
2828
"ch.qos.logback.contrib" % "logback-jackson" % logbackJson exclude("com.fasterxml.jackson.core", "jackson-databind"),
2929
"com.fasterxml.jackson.core" % "jackson-databind" % "2.15.1",
@@ -33,19 +33,19 @@ libraryDependencies ++= Seq(
3333
"com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion,
3434
"com.typesafe.akka" %% "akka-http-xml" % akkaHttpVersion,
3535
"com.amazonaws" % "aws-java-sdk-s3" % "1.12.470",
36-
"org.apache.kafka" % "kafka-clients" % "3.3.2",
36+
"org.apache.kafka" % "kafka-clients" % "3.4.0",
3737
"org.apache.ranger" % "ranger-plugins-common" % "2.4.0" exclude("org.eclipse.jetty", "jetty-io") exclude("com.amazonaws", "aws-java-sdk-bundle") exclude("org.elasticsearch", "elasticsearch-x-content") exclude("org.elasticsearch", "elasticsearch") exclude("org.apache.hadoop", "hadoop-common"),
3838
"org.apache.hadoop" % "hadoop-common" % "3.3.5" exclude("org.apache.hadoop.thirdparty", "hadoop-shaded-protobuf_3_7") exclude("org.eclipse.jetty", "jetty-io") exclude("org.apache.zookeeper", "zookeeper") exclude("com.google.protobuf", "protobuf-java"), //needed for ranger 2.3.0 - if vulnerabilities are fixed remove this
3939
"com.lightbend.akka" %% "akka-stream-alpakka-xml"% "3.0.4",
4040
"io.dropwizard.metrics" % "metrics-core" % metricVersion,
4141
"io.dropwizard.metrics" % "metrics-jmx" % metricVersion,
42-
"com.auth0" % "java-jwt" % "4.2.1",
42+
"com.auth0" % "java-jwt" % "4.3.0",
4343
"com.github.cb372" %% "scalacache-core" % "0.28.0",
4444
"com.github.cb372" %% "scalacache-caffeine" % "0.28.0",
4545
"com.typesafe.akka" %% "akka-testkit" % akkaVersion % Test,
4646
"com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion % Test,
4747
"org.scalatest" %% "scalatest" % "3.2.16" % "it,test",
48-
"com.amazonaws" % "aws-java-sdk-sts" % "1.12.470" % IntegrationTest,
48+
"com.amazonaws" % "aws-java-sdk-sts" % "1.12.471" % IntegrationTest,
4949
)
5050
dependencyOverrides ++= Seq(
5151
"net.minidev" % "json-smart" % "2.4.11",

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version = 1.7.1
1+
sbt.version =1.8.3

src/it/scala/com/ing/wbaa/rokku/proxy/RokkuS3ProxyItTest.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class RokkuS3ProxyItTest extends AsyncWordSpec with Diagrams
7878
def withSdkToMockProxy(testCode: (AWSSecurityTokenService, Authority) => Future[Assertion]): Future[Assertion] = {
7979
val proxy: RokkuS3Proxy = new RokkuS3Proxy with RequestHandlerS3
8080
with FilterRecursiveListBucketHandler with AuthenticationProviderSTS
81-
with AuthorizationProviderRanger with SignatureProviderAws
81+
with AccessControlProvider with SignatureProviderAws
8282
with MessageProviderKafka with AuditLogProvider with MemoryUserRequestQueue with RequestParser {
8383
override implicit lazy val system: ActorSystem = testSystem
8484
override def materializer: Materializer = Materializer(system)
@@ -87,7 +87,7 @@ class RokkuS3ProxyItTest extends AsyncWordSpec with Diagrams
8787
override val stsSettings: StsSettings = StsSettings(testSystem)
8888
override val kafkaSettings: KafkaSettings = KafkaSettings(testSystem)
8989

90-
override protected def rangerSettings: RangerSettings = RangerSettings(testSystem)
90+
override protected def accessControlProviderSettings: AccessControlProviderSettings = AccessControlProviderSettings(testSystem)
9191

9292
override def isUserAuthorizedForRequest(request: S3Request, user: User)(implicit id: RequestId): Boolean = {
9393
user match {

src/it/scala/com/ing/wbaa/rokku/proxy/provider/AuthorizationProviderRangerItTest.scala renamed to src/it/scala/com/ing/wbaa/rokku/proxy/provider/AccessControlProviderRangerItTest.scala

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.ing.wbaa.rokku.proxy.provider
33
import java.net.InetAddress
44
import akka.actor.ActorSystem
55
import akka.http.scaladsl.model.RemoteAddress
6-
import com.ing.wbaa.rokku.proxy.config.RangerSettings
6+
import com.ing.wbaa.rokku.proxy.config.AccessControlProviderSettings
77
import com.ing.wbaa.rokku.proxy.data._
88
import com.ing.wbaa.rokku.proxy.handler.exception.RokkuListingBucketsException
99
import org.scalatest.Assertion
@@ -12,7 +12,7 @@ import org.scalatest.wordspec.AsyncWordSpec
1212

1313
import scala.concurrent.Future
1414

15-
class AuthorizationProviderRangerItTest extends AsyncWordSpec with Diagrams {
15+
class AccessControlProviderRangerItTest extends AsyncWordSpec with Diagrams {
1616
final implicit val testSystem: ActorSystem = ActorSystem.create("test-system")
1717

1818
implicit val requestId: RequestId = RequestId("test")
@@ -57,11 +57,11 @@ class AuthorizationProviderRangerItTest extends AsyncWordSpec with Diagrams {
5757
* @param testCode Code that accepts the created authorization provider
5858
* @return Assertion
5959
*/
60-
def withAuthorizationProviderRanger(rangerTestSettings: RangerSettings =
61-
RangerSettings(testSystem))
62-
(testCode: AuthorizationProviderRanger => Future[Assertion]): Future[Assertion] = {
63-
testCode(new AuthorizationProviderRanger {
64-
override def rangerSettings: RangerSettings = rangerTestSettings
60+
def withAuthorizationProviderRanger(rangerTestSettings: AccessControlProviderSettings =
61+
AccessControlProviderSettings(testSystem))
62+
(testCode: AccessControlProvider => Future[Assertion]): Future[Assertion] = {
63+
testCode(new AccessControlProvider {
64+
override def accessControlProviderSettings: AccessControlProviderSettings = rangerTestSettings
6565
})
6666
}
6767

@@ -108,14 +108,14 @@ class AuthorizationProviderRangerItTest extends AsyncWordSpec with Diagrams {
108108
accessType = Read(), clientIPAddress = clientIPAddress, headerIPs = headerIPs), user))
109109
}
110110

111-
"throw exception allow-list-buckets set to false" in withAuthorizationProviderRanger(new RangerSettings(testSystem.settings.config) {
111+
"throw exception allow-list-buckets set to false" in withAuthorizationProviderRanger(new AccessControlProviderSettings(testSystem.settings.config) {
112112
override val listBucketsEnabled: Boolean = false
113113
}) { apr =>
114114
assertThrows[RokkuListingBucketsException](apr.isUserAuthorizedForRequest(s3Request.copy(s3BucketPath = None, s3Object = None,
115115
accessType = Read(), clientIPAddress = clientIPAddress, headerIPs = headerIPs), user))
116116
}
117117

118-
"does not authorize allow-create-delete-buckets set to false" in withAuthorizationProviderRanger(new RangerSettings(testSystem.settings.config) {
118+
"does not authorize allow-create-delete-buckets set to false" in withAuthorizationProviderRanger(new AccessControlProviderSettings(testSystem.settings.config) {
119119
override val createDeleteBucketsEnabled: Boolean = false
120120
}) { apr =>
121121
assert(!apr.isUserAuthorizedForRequest(s3Request.copy(s3Object = None, accessType = Put(),
@@ -124,25 +124,25 @@ class AuthorizationProviderRangerItTest extends AsyncWordSpec with Diagrams {
124124
clientIPAddress = clientIPAddress, headerIPs = headerIPs), user))
125125
}
126126

127-
"does authorize creating bucket for an admin" in withAuthorizationProviderRanger(new RangerSettings(testSystem.settings.config) {
127+
"does authorize creating bucket for an admin" in withAuthorizationProviderRanger(new AccessControlProviderSettings(testSystem.settings.config) {
128128
}) { apr =>
129129
assert(apr.isUserAuthorizedForRequest(s3Request.copy(s3Object = None, accessType = Put(),
130130
clientIPAddress = clientIPAddress, headerIPs = headerIPs), adminUser))
131131
}
132132

133-
"does authorize deleting bucket for an admin" in withAuthorizationProviderRanger(new RangerSettings(testSystem.settings.config) {
133+
"does authorize deleting bucket for an admin" in withAuthorizationProviderRanger(new AccessControlProviderSettings(testSystem.settings.config) {
134134
}) { apr =>
135135
assert(apr.isUserAuthorizedForRequest(s3Request.copy(s3Object = None, accessType = Delete(),
136136
clientIPAddress = clientIPAddress, headerIPs = headerIPs), adminUser))
137137
}
138138

139-
"does not authorize creating bucket for a user" in withAuthorizationProviderRanger(new RangerSettings(testSystem.settings.config) {
139+
"does not authorize creating bucket for a user" in withAuthorizationProviderRanger(new AccessControlProviderSettings(testSystem.settings.config) {
140140
}) { apr =>
141141
assert(!apr.isUserAuthorizedForRequest(s3Request.copy(s3Object = None, accessType = Put(),
142142
clientIPAddress = clientIPAddress, headerIPs = headerIPs), user))
143143
}
144144

145-
"does not authorize deleting bucket for a user" in withAuthorizationProviderRanger(new RangerSettings(testSystem.settings.config) {
145+
"does not authorize deleting bucket for a user" in withAuthorizationProviderRanger(new AccessControlProviderSettings(testSystem.settings.config) {
146146
}) { apr =>
147147
assert(!apr.isUserAuthorizedForRequest(s3Request.copy(s3Object = None, accessType = Delete(),
148148
clientIPAddress = clientIPAddress, headerIPs = headerIPs), user))
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.ing.wbaa.rokku.proxy.security;
2+
3+
public interface AccessControl {
4+
String AUDIT_ENABLED_PARAM = "auditEnabled";
5+
6+
void init();
7+
8+
boolean isAccessAllowed(AccessControlRequest request);
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.ing.wbaa.rokku.proxy.security;
2+
3+
import java.util.List;
4+
import java.util.Set;
5+
public record AccessControlRequest(
6+
String user,
7+
Set<String> userGroups,
8+
String userRole,
9+
String path,
10+
String accessType,
11+
String action,
12+
String clientIpAddress,
13+
String remoteIpAddress,
14+
List<String> forwardedIpAddresses) {
15+
}

src/main/resources/application.conf

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ rokku {
44
bind = ${?ROKKU_HTTP_BIND}
55
port = ${?ROKKU_HTTP_PORT}
66
}
7-
ranger {
7+
access-control {
88
allow-list-buckets = ${?ROKKU_ALLOW_LIST_BUCKETS}
99
allow-create-delete-buckets = ${?ROKKU_ALLOW_CREATE_DELETE_BUCKETS}
10-
user-domain-postfix = ${?ROKKU_RANGER_USER_DOMAIN_POSTFIX}
11-
enabled-audit = ${?ROKKU_RANGER_ENABLED_AUDIT}
12-
role-prefix = ${?ROKKU_RANGER_ROLE_PREFIX}
13-
app_id = ${?ROKKU_RANGER_API_ID}
10+
enabled-audit = ${?ROKKU_ENABLED_AUDIT}
11+
class-name = ${?ROKKU_ACCESS_CONTROL_CLASS_NAME}
12+
plugin-params {
13+
appId = ${?ROKKU_RANGER_API_ID}
14+
userDomainPostfix = ${?ROKKU_RANGER_USER_DOMAIN_POSTFIX}
15+
rolePrefix = ${?ROKKU_RANGER_ROLE_PREFIX}
16+
}
1417
}
1518
storage.s3 {
1619
# Settings for reaching backing storage.

src/main/resources/reference.conf

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,19 @@ rokku {
55
port = 8987
66
}
77

8-
ranger {
9-
# Settings for reaching Ranger.
10-
11-
# make sure the service_type is equal to what is specified in
12-
# ranger-s3-security.xml
13-
service_type = "s3"
14-
app_id = "testservice"
8+
access-control {
159
allow-list-buckets = true
1610
allow-create-delete-buckets = true
17-
user-domain-postfix = ""
1811
enabled-audit = false
19-
role-prefix = "role_"
12+
class-name = "com.ing.wbaa.rokku.proxy.provider.AccessControlProviderRanger"
13+
plugin-params {
14+
appId = "testservice"
15+
# make sure the service_type is equal to what is specified in
16+
# ranger-s3-security.xml
17+
serviceType = "s3"
18+
userDomainPostfix = ""
19+
rolePrefix = "role_"
20+
}
2021
}
2122

2223
storage.s3 {

0 commit comments

Comments
 (0)