Skip to content

Commit

Permalink
Merge pull request #62 from ing-bank/feature/workflows
Browse files Browse the repository at this point in the history
Feature/workflows
  • Loading branch information
jahnestacado committed Sep 14, 2022
2 parents fa5a6e1 + 6d9403b commit 58de90c
Show file tree
Hide file tree
Showing 45 changed files with 1,113 additions and 934 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/build-feature.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Rokku-STS feature branch build

on:
push:
branches-ignore:
- master

env:
DOCKER_REPO: wbaa/rokku-sts

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: 'sbt'
- name: Run docker-compose
run: docker-compose up -d && ./scripts/waitForContainerSetup.sh
- name: Run tests
run: sbt clean coverage test it:test coverageReport

upload-image:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v2
with:
fetch-depth: '0'
- name: Build and publish docker image
run: |
# Login to docker
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
# Build docker image
echo "Build image $DOCKER_REPO:${GITHUB_REF##*/}";
ROKKU_STS_VERSION=${GITHUB_REF##*/} sbt clean docker:publish;
62 changes: 62 additions & 0 deletions .github/workflows/build-master.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Rokku-STS master branch build

on:
push:
branches:
- master

env:
DOCKER_REPO: wbaa/rokku-sts

jobs:

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: 'sbt'
- name: Run docker-compose
run: docker-compose up -d && ./scripts/waitForContainerSetup.sh
- name: Run tests
run: sbt clean coverage test it:test coverageReport

tag:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v2
with:
fetch-depth: '0'
- name: Bump version and push tag
uses: anothrNick/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
WITH_V: true
VERBOSE: true
DEFAULT_BUMP: patch

upload-image:
runs-on: ubuntu-latest
needs: tag
steps:
- uses: actions/checkout@v2
with:
fetch-depth: '0'
- name: Build and publish docker image
run: |
# Login to docker
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
# Build docker image
ROKKU_STS_VERSION=$(git describe --tags --abbrev=0) sbt clean docker:publish;
echo "Built image $DOCKER_REPO:$(git describe --tags --abbrev=0)";
# Add latest tag
docker tag $DOCKER_REPO:$(git describe --tags --abbrev=0) $DOCKER_REPO:latest;
docker push $DOCKER_REPO:$(git describe --tags --abbrev=0)
docker push $DOCKER_REPO:latest
17 changes: 17 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Rokku-STS release

on:
push:
tags:
- "*"

jobs:
tagged-release:
name: "Tagged Release"
runs-on: "ubuntu-latest"

steps:
- uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.PAT }}"
prerelease: false
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,11 @@ snapshots
# Log files
*.log
/bin/

.bloop/
.bsp/
.metals/
.scalafmt.conf
project/.bloop/
project/metals.sbt
.vscode
6 changes: 1 addition & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,7 @@ To get a quickstart on running the Rokku STS, you'll need the following:
The STS service is dependant on two services:

* [Keycloak](https://www.keycloak.org/) for MFA authentication of users.
* A persistence store to maintain the user and session tokens issued, in the current infrastructure that is [MariaDB](https://mariadb.org).

For the persistence, Rokku STS does not autogenerate the tables required. So if you launch your own MariaDB database,
you will need to create the tables as well. You can find the script to create the database, and the related tables
[here](https://github.com/ing-bank/rokku-dev-mariadb/blob/master/database/rokkudb.sql).
* [Redis] A persistence store to maintain the user and session tokens issued


## Test (mock version)
Expand Down
28 changes: 17 additions & 11 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import com.typesafe.sbt.packager.docker
import com.typesafe.sbt.packager.docker.ExecCmd
import com.typesafe.sbt.packager.docker.Cmd
import scalariform.formatter.preferences._

val rokkuStsVersion = scala.sys.env.getOrElse("ROKKU_STS_VERSION", "SNAPSHOT")
Expand All @@ -14,7 +14,7 @@ scalacOptions := Seq(
"-encoding", "utf-8",
"-target:11",
"-feature",
"-Xlint",
"-Xlint:-byname-implicit",
"-Xfatal-warnings",
)

Expand All @@ -25,7 +25,7 @@ assemblyJarName in assembly := "rokku-sts.jar"

val akkaVersion = "2.6.19"
val akkaHttpVersion = "10.2.9"
val keycloakVersion = "16.1.1"
val keycloakVersion = "19.0.0"
val logbackJson = "0.1.5"

libraryDependencies ++= Seq(
Expand All @@ -42,24 +42,21 @@ libraryDependencies ++= Seq(
"org.keycloak" % "keycloak-admin-client" % keycloakVersion,
"org.jboss.logging" % "jboss-logging" % "3.5.0.Final",
"org.apache.httpcomponents" % "httpclient" % "4.5.13",
"org.mariadb.jdbc" % "mariadb-java-client" % "2.3.0",
"ch.qos.logback.contrib" % "logback-json-classic" % logbackJson,
"ch.qos.logback.contrib" % "logback-jackson" % logbackJson,
"com.fasterxml.jackson.core" % "jackson-databind" % "2.13.3",
"com.auth0" % "java-jwt" % "4.0.0",
"com.bettercloud" % "vault-java-driver" % "5.1.0",
"redis.clients" % "jedis" % "4.3.0-m1",
"org.scalatest" %% "scalatest" % "3.2.13" % "test, it",
"com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion % Test,
"com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion % Test,
"com.amazonaws" % "aws-java-sdk-sts" % "1.12.278" % IntegrationTest,
)


configs(IntegrationTest)

Defaults.itSettings

parallelExecution in IntegrationTest := false
Global / lintUnusedKeysOnLoad := false

javaOptions in Universal ++= Seq(
"-Dlogback.configurationFile=/rokku/logback.xml",
Expand All @@ -70,8 +67,16 @@ enablePlugins(JavaAppPackaging)
fork := true

dockerExposedPorts := Seq(12345)
dockerCommands += ExecCmd("ENV", "PROXY_HOST", "0.0.0.0")
dockerBaseImage := "openjdk:8u171-jre-slim-buster"

dockerCommands ++= Seq(
Cmd("ENV", "PROXY_HOST", "0.0.0.0"),
Cmd("USER", "root"),
Cmd("RUN", "apt-get update && apt-get upgrade -y"),
Cmd("USER", "1001"),
)


dockerBaseImage := "openjdk:11-slim-bullseye"
dockerAlias := docker.DockerAlias(Some("docker.io"), Some("wbaa"), "rokku-sts", Some(rokkuStsVersion))

scalariformPreferences := scalariformPreferences.value
Expand All @@ -83,4 +88,5 @@ scalariformPreferences := scalariformPreferences.value
.setPreference(SingleCasePatternOnNewline, false)

scalastyleFailOnError := true

scalariformItSettings
scalariformAutoformat := true
9 changes: 5 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ services:
ports:
- 8080:8080

mariadb:
image: wbaa/rokku-dev-mariadb:0.0.8
redis:
image: redislabs/redisearch
environment:
- MYSQL_ROOT_PASSWORD=admin
- TZ=Europe/Amsterdam
command: "redis-server --requirepass password --loadmodule '/usr/lib/redis/modules/redisearch.so'"
ports:
- 3307:3306
- 6379:6379

vault:
image: vault:1.4.2
Expand Down
Empty file modified scripts/rokku-assume-role.sh
100644 → 100755
Empty file.
Empty file modified scripts/rokku-get-session-token.sh
100644 → 100755
Empty file.
14 changes: 12 additions & 2 deletions waitForContainerSetup.sh → scripts/waitForContainerSetup.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@ set -e
# Max query attempts before consider setup failed
MAX_TRIES=90

function rokkuKeycloak() {
function keycloak() {
docker-compose logs keycloak | grep "Admin console listening"
}

function redis() {
docker-compose logs redis | grep "Ready to accept connections"
}

function vault() {
docker-compose logs vault | grep "upgrading keys finished"
}

function waitUntilServiceIsReady() {
attempt=1
while [ $attempt -le $MAX_TRIES ]; do
Expand All @@ -27,4 +35,6 @@ function waitUntilServiceIsReady() {
fi
}

waitUntilServiceIsReady rokkuKeycloak "Keycloack ready"
waitUntilServiceIsReady redis "Redis is ready"
waitUntilServiceIsReady vault "Vault is ready"
waitUntilServiceIsReady keycloak "Keycloack is ready"
7 changes: 4 additions & 3 deletions src/it/scala/com/ing/wbaa/rokku/sts/AWSSTSClient.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.ing.wbaa.rokku.sts

import akka.http.scaladsl.model.Uri.Authority
import com.amazonaws.auth.{AWSStaticCredentialsProvider, BasicAWSCredentials}
import com.amazonaws.auth.AWSStaticCredentialsProvider
import com.amazonaws.auth.BasicAWSCredentials
import com.amazonaws.client.builder.AwsClientBuilder
import com.amazonaws.regions.Regions
import com.amazonaws.services.securitytoken.{AWSSecurityTokenService, AWSSecurityTokenServiceClientBuilder}

import com.amazonaws.services.securitytoken.AWSSecurityTokenService
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder

trait AWSSTSClient {

Expand Down
55 changes: 29 additions & 26 deletions src/it/scala/com/ing/wbaa/rokku/sts/StsServiceItTest.scala
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
package com.ing.wbaa.rokku.sts

import java.time.Instant

import akka.actor.ActorSystem
import akka.http.scaladsl.model.Uri.{Authority, Host}
import akka.http.scaladsl.model.Uri.Authority
import akka.http.scaladsl.model.Uri.Host
import com.amazonaws.services.securitytoken.AWSSecurityTokenService
import com.amazonaws.services.securitytoken.model.{AWSSecurityTokenServiceException, AssumeRoleRequest, GetSessionTokenRequest}
import com.ing.wbaa.rokku.sts.config.{HttpSettings, KeycloakSettings, MariaDBSettings, StsSettings, VaultSettings}
import com.amazonaws.services.securitytoken.model.AWSSecurityTokenServiceException
import com.amazonaws.services.securitytoken.model.AssumeRoleRequest
import com.amazonaws.services.securitytoken.model.GetSessionTokenRequest
import com.ing.wbaa.rokku.sts.config.HttpSettings
import com.ing.wbaa.rokku.sts.config.KeycloakSettings
import com.ing.wbaa.rokku.sts.config.RedisSettings
import com.ing.wbaa.rokku.sts.config.StsSettings
import com.ing.wbaa.rokku.sts.config.VaultSettings
import com.ing.wbaa.rokku.sts.data.UserAssumeRole
import com.ing.wbaa.rokku.sts.data.Username
import com.ing.wbaa.rokku.sts.data.aws._
import com.ing.wbaa.rokku.sts.data.{UserAssumeRole, UserName}
import com.ing.wbaa.rokku.sts.helper.{KeycloackToken, OAuth2TokenRequest}
import com.ing.wbaa.rokku.sts.keycloak.{ KeycloakClient, KeycloakTokenVerifier }
import com.ing.wbaa.rokku.sts.helper.KeycloackToken
import com.ing.wbaa.rokku.sts.helper.OAuth2TokenRequest
import com.ing.wbaa.rokku.sts.keycloak.KeycloakClient
import com.ing.wbaa.rokku.sts.keycloak.KeycloakTokenVerifier
import com.ing.wbaa.rokku.sts.service.UserTokenDbService
import com.ing.wbaa.rokku.sts.service.db.MariaDb
import com.ing.wbaa.rokku.sts.service.db.dao.STSUserAndGroupDAO
import com.ing.wbaa.rokku.sts.service.db.Redis
import com.ing.wbaa.rokku.sts.service.db.RedisModel
import com.ing.wbaa.rokku.sts.service.db.dao.STSUserDAO
import com.ing.wbaa.rokku.sts.vault.VaultService
import org.scalatest.Assertion
import org.scalatest.diagrams.Diagrams
import org.scalatest.wordspec.AsyncWordSpec

import java.time.Instant
import scala.concurrent.ExecutionContextExecutor
import scala.concurrent.Future
import scala.concurrent.duration.Duration
import scala.concurrent.{ExecutionContextExecutor, Future}
import scala.util.Random

class StsServiceItTest extends AsyncWordSpec with Diagrams
Expand Down Expand Up @@ -51,13 +62,7 @@ class StsServiceItTest extends AsyncWordSpec with Diagrams

// Fixture for starting and stopping a test proxy that tests can interact with.
def withTestStsService(testCode: Authority => Future[Assertion]): Future[Assertion] = {
val sts = new RokkuStsService
with KeycloakTokenVerifier
with UserTokenDbService
with STSUserAndGroupDAO
with MariaDb
with VaultService
with KeycloakClient {
val sts = new RokkuStsService with KeycloakTokenVerifier with UserTokenDbService with STSUserDAO with Redis with RedisModel with VaultService with KeycloakClient {
override implicit def system: ActorSystem = testSystem

override protected[this] def httpSettings: HttpSettings = rokkuHttpSettings
Expand All @@ -66,15 +71,15 @@ class StsServiceItTest extends AsyncWordSpec with Diagrams

override protected[this] def stsSettings: StsSettings = StsSettings(testSystem)

override protected[this] def mariaDBSettings: MariaDBSettings = new MariaDBSettings(testSystem.settings.config)
override protected[this] def redisSettings: RedisSettings = new RedisSettings(testSystem.settings.config)

override protected[this] def insertToken(awsSessionToken: AwsSessionToken, username: UserName, expirationDate: AwsSessionTokenExpiration): Future[Boolean] =
override protected[this] def insertToken(awsSessionToken: AwsSessionToken, username: Username, expirationDate: AwsSessionTokenExpiration): Future[Boolean] =
Future.successful(true)

override protected[this] def insertToken(awsSessionToken: AwsSessionToken, username: UserName, role: UserAssumeRole, expirationDate: AwsSessionTokenExpiration): Future[Boolean] =
override protected[this] def insertToken(awsSessionToken: AwsSessionToken, username: Username, role: UserAssumeRole, expirationDate: AwsSessionTokenExpiration): Future[Boolean] =
Future.successful(true)

override protected[this] def getToken(awsSessionToken: AwsSessionToken, userName: UserName): Future[Option[(UserName, UserAssumeRole, AwsSessionTokenExpiration)]] =
override protected[this] def getToken(awsSessionToken: AwsSessionToken, username: Username): Future[Option[(Username, UserAssumeRole, AwsSessionTokenExpiration)]] =
Future.successful(None)

override def generateAwsSession(duration: Option[Duration]): AwsSession = AwsSession(
Expand All @@ -101,8 +106,8 @@ class StsServiceItTest extends AsyncWordSpec with Diagrams
"return credentials for valid token" in withAwsClient { stsAwsClient =>
withOAuth2TokenRequest(validCredentials) { keycloakToken =>
val credentials = stsAwsClient.getSessionToken(new GetSessionTokenRequest()
.withTokenCode(keycloakToken.access_token))
.getCredentials
.withTokenCode(keycloakToken.access_token))
.getCredentials

assert(!credentials.getAccessKeyId.isEmpty)
assert(!credentials.getSecretAccessKey.isEmpty)
Expand Down Expand Up @@ -150,7 +155,6 @@ class StsServiceItTest extends AsyncWordSpec with Diagrams
}
}


"throw AWSSecurityTokenServiceException because there is invalid token" in withAwsClient { stsAwsClient =>
withOAuth2TokenRequest(invalidCredentials) { keycloakToken =>
assertThrows[AWSSecurityTokenServiceException] {
Expand All @@ -163,6 +167,5 @@ class StsServiceItTest extends AsyncWordSpec with Diagrams
}
}


}
}
Loading

0 comments on commit 58de90c

Please sign in to comment.