LoginSignup
3
2

More than 3 years have passed since last update.

IAPに対応しているGAEにアクセスする

Posted at

概要

GCPにあるGAEに対してアクセスする場合、認証のためにIAPをつけることが多いハズ
その際にrequest clientに対して認証情報を付ける方法についてまとめる

サービスアカウントを作る

サービスアカウントは以下の通りに作成できる
https://cloud.google.com/iam/docs/creating-managing-service-accounts?hl=ja

先程のサービスアカウントをIAPのアクセスユーザとして追加する

先程のサービスアカウントに対してGAEに対する権限を付ける。(IAP-secured Web App Userとして先程のサービスアカウントをつける。

コードのサンプル実装

build.gradle
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    // https://mvnrepository.com/artifact/com.google.api-client/google-api-client
    implementation group: 'com.google.api-client', name: 'google-api-client', version: '1.30.9'
    // https://mvnrepository.com/artifact/com.google.auth/google-auth-library-oauth2-http
    implementation group: 'com.google.auth', name: 'google-auth-library-oauth2-http', version: '0.20.0'
}

とりあえず依存関係にgoogleのapi-clientとauthを追加する。

IapRequest.kt
// https://cloud.google.com/iap/docs/authentication-howto?hl=ja#iap_make_request-javaのコードを参考にKotlinにしただけ
import com.google.api.client.http.HttpRequest
import com.google.api.client.http.HttpRequestInitializer
import com.google.api.client.http.HttpTransport
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.auth.http.HttpCredentialsAdapter
import com.google.auth.oauth2.GoogleCredentials
import com.google.auth.oauth2.IdTokenCredentials
import com.google.auth.oauth2.IdTokenProvider
import java.io.File

class IapRequest(
    serviceAccountFile: File
) {
    private val IAM_SCOPE = "https://www.googleapis.com/auth/iam"
    private val httpTransport: HttpTransport = NetHttpTransport()
    private val idTokenProvider: IdTokenProvider

    init {
        val credentials: GoogleCredentials =
            GoogleCredentials.fromStream(serviceAccountFile.inputStream())
                .createScoped(setOf(IAM_SCOPE))
        if (credentials !is IdTokenProvider) {
            throw Exception("Google credentials : credentials that can provide id tokens expected")
        }
        idTokenProvider = credentials
    }

    /**
     * Clone request and add an IAP Bearer Authorization header with signed JWT token.
     *
     * @param request Request to add authorization header
     * @param iapClientId OAuth 2.0 client ID for IAP protected resource
     * @return Clone of request with Bearer style authorization header with signed jwt token.
     * @throws Exception exception creating signed JWT
     */
    fun build(request: HttpRequest, iapClientId: String): HttpRequest {
        val idTokenProvider: IdTokenProvider = idTokenProvider
        val credentials: IdTokenCredentials = IdTokenCredentials.newBuilder()
            .setIdTokenProvider(idTokenProvider)
            .setTargetAudience(iapClientId)
            .build()

        val httpRequestInitializer: HttpRequestInitializer = HttpCredentialsAdapter(credentials)
        return httpTransport
            .createRequestFactory(httpRequestInitializer)
            .buildRequest(request.requestMethod, request.url, request.content)
    }
}

com.google.auth.oauth2.IdTokenProviderがBetaがunstableになっているからというwarningがでているが気にしない。
処理としては、ベースとなるGoogleのRequest Objectに対してauthorization headerをつけるAdapterを追加している

GoogleCredentials.fromStream(...) で認証ファイルを読み込んでくれている

Main.kt
import com.google.api.client.http.GenericUrl
import com.google.api.client.http.HttpRequest
import com.google.api.client.http.HttpResponseException
import com.google.api.client.http.HttpTransport
import com.google.api.client.http.javanet.NetHttpTransport
import java.io.File

// 先程のGAEのURL
val protectedUr = "https://hoge.appspot.com/"
// クライアント ID (IAPのOAuthクライアントを編集)
val clientId = "hogehoge"

fun main() {
    auth()
}

fun auth() {
    val httpTransport: HttpTransport = NetHttpTransport()
    val request =
        IapRequest(File(ClassLoader.getSystemResource("service-account.json").toURI()))
            .build(
                httpTransport.createRequestFactory().buildGetRequest(GenericUrl(protectedUr)),
                clientId
            )
    try {
        val response = request.execute()
        println("content: ${response.parseAsString()}")
    } catch (e: HttpResponseException) {
        println(e)
    }
}

ここは実際に使っているだけ
ユースケースとしてGAEのサービス1つづつに対してそれぞれIAP許可設定をつけることがあるので、IAP Request作成時にサービスアカウントの認証ファイルを渡す。

まとめ

課題として、このコードの場合GoogleのHttpClientに依存しているので、他のHttpClientでも使えるようにしたい。。。コードを追っていく必要がある。

もしくは以下の手順を地道にコードにしていくか
https://cloud.google.com/iap/docs/app-engine-quickstart?hl=ja#iap-access

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2