0
0

More than 1 year has passed since last update.

Kyma runtimeでCloud Foundry CLIを実行するAPIを作成

Last updated at Posted at 2023-03-07

はじめに

先日、SAP Build Process AutomationでBTPのユーザ登録を自動化するという記事を書きました。記事の中で紹介したのは、Process Automationのワークフローをベースとして、申請されたユーザをBTPのサブアカウントに登録したり、ロールコレクションを付与したりするフローでした。
image.png

改善ポイントとして残っていたのが、Cloud Foundryのスペースへのユーザ登録でした。スペースへのユーザ登録ができるHTTPベースのAPIが見つからなかったため、上記の記事ではシステム管理者がマニュアルで行うこととしていました。
ワークフローからユーザ登録をするためにはCloud Foundry CLIをラップするAPIが必要になります。そこで今回は以下のような構成でAPIを作成することにしました。

  • CFコマンドを実行するためのスクリプトを作成
  • スクリプトを実行するNode.jsアプリを作成し、APIを公開

Cloud Foundry CLIを実行環境にインストールする必要があるため、Kyma runtimeを利用します。
image.png

ステップ

  1. スクリプトの作成
  2. Node.jsアプリの作成
  3. Dockerイメージの作成
  4. シークレットの作成
  5. Deploymentの作成

プロジェクトの構成は以下のようになっています。
image.png

1. スクリプトの作成

以下のスクリプトを作成しました。

src/script.sh
#!/bin/bash

if [ -z "$1" ] || [ -z "$2" ]; then
    echo "Usage: $0 USER ROLE"
    exit 1
fi

# Assign positional arguments to variables
USER=$1
ROLE=$2

# login
cf login -a $CF_API_URL -u $CF_USERNAME -p $CF_PASSWORD -o $CF_ORG -s $CF_SPACE

# add a user to space
result=$(cf set-space-role $USER $CF_ORG $CF_SPACE $ROLE | awk '{print $NF}')

echo $result
if [[ "$result" == *OK ]]; then
    echo "OK"
else
    echo "Error"
    exit 1
fi

このスクリプトは引数にユーザと割り当てたいスペースのロールを受け取ります。

実行方法(例)
./script.sh user1@gmail.com SpaceDeveloper

スクリプトで行っているのは、Cloud Foundryにログインしてユーザにロールを割り当てることです。スペースにユーザが未登録の場合は、cf set-space-roleコマンドによりユーザが追加されます。$CF_API_URL$CF_USERNAME等のパラメータは環境変数として定義します。

cf set-space-roleコマンドは、以下のような結果を返します。

ロールの割り当てに成功した場合(正常)
Assigning role SpaceAuditor to user xxx@gmail.com in org f83f5860trial / space dev as xxx@gmail.com...
OK
すでにロールが割り当て済みの場合(正常)
Assigning role SpaceAuditor to user mio.fujita.01@gmail.com in org f83f5860trial / space dev as xxx@gmail.com...
User 'xxx@gmail.com' already has role 'SpaceAuditor' in org 'f83f5860trial' / space 'dev'.
OK
サブアカウントに存在しないユーザを指定した場合(異常)
Assigning role SpaceAuditor to user mio.fujita.02@gmail.com in org f83f5860trial / space dev as xxx@gmail.com...
No user exists with the username 'xxx@gmail.com'.
FAILED

よって、結果の末尾が"OK"か否かによって、スクリプトを正常終了するか異常終了するかを判断します。

2. Node.jsアプリの作成

Node.jsアプリは/spaceuserというエンドポイントを公開します。ボディ(JSON)に設定されたuser, roleという2つの項目を先ほどのスクリプトに渡します。

src/server.js
const express = require('express')
const { execSync } = require('child_process')

const app = express()
const port = process.env.PORT || 8080

app.use(express.json())

app.post('/spaceuser', (req, res) => {
  console.log('Received data:', req.body)
  const user = sanitize(req.body.user)
  const role= sanitize(req.body.role)

  try {
    execSync(`./script.sh ${user} ${role}`)
  } catch (error) {
    return res.status(400).send(error.message);
  }

  res.send('Space user was addedded successfully.')
})

function sanitize (input) {
    return input.split("|")[0]
}

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

sanitizeというファンクションは、例えば"role": "SpaceDeveloper" | ls"のように任意のコマンドを渡されても後ろのコマンドが実行されないように、 パイプの前の項目のみを取得します。

3. Dockerイメージの作成

以下のDockerfileを作成します。

# syntax=docker/dockerfile:1

FROM node:latest

# install cf cli
RUN wget -q -O - https://packages.cloudfoundry.org/debian/cli.cloudfoundry.org.key | apt-key add -
RUN echo "deb https://packages.cloudfoundry.org/debian stable main" | tee /etc/apt/sources.list.d/cloudfoundry-cli.list
RUN apt-get update
RUN apt-get install cf8-cli

WORKDIR /app
COPY ["src/package.json", "src/package-lock.json*", "./"]
RUN npm install
COPY src/ .
# remove windows style carriage returns
RUN sed -i -e 's/\r$//' script.sh
CMD [ "node", "server.js" ]

nodeをベースイメージとして、そこにCLoud Foundry CLIをインストールします。インストール方法は以下のページを参考にしました。
https://docs.cloudfoundry.org/cf-cli/install-go-cli.html#pkg-linux

以下の部分は、私がWindowsでDockerイメージを作成していることに起因する問題への対応です。

# remove windows style carriage returns
RUN sed -i -e 's/\r$//' script.sh

私はスクリプトやNode.jsアプリの開発はBusiness Application Studio(Linux環境)で行い、Dockerイメージを作成するためにWindowsの端末にGit経由で引っ張ってくるという開発を行っていました。するとWindowsに持ってきたときにスクリプトファイルにWindowsスタイルの改行コードが入り込み、Kyma runtimeでスクリプトを実行しようとすると./script.sh: not foundというエラーになりました。対応として、イメージ作成時にWindowsスタイルの改行コードを除去することにしました。

APIを実行したときのエラー内容(Windowsスタイルの改行コードが含まれている場合)
image.png

以下のコマンドでイメージを作成し、Docker Hubにプッシュします。

docker build -t <ユーザ名>/<イメージ>:<タグ> .
docker image push <ユーザ名>/<イメージ>:<タグ>

4. シークレットの作成

スクリプトの中で環境変数として使いたいパラメータをシークレットとして登録します。
image.png
image.png
image.png

今回はUIから作成しましたが、kubectlのコマンドを使って以下のように登録することもできます。(改行はPower Shell向けになっているので、Linux, Macの場合は\に変更)

kubectl create secret generic env-cfcommand `
  --namespace default `
  --from-literal=CF_API_URL=apiUrl `
  --from-literal=CF_USERNAME=userName `
  --from-literal=CF_PASSWORD=password `
  --from-literal=CF_ORG=org `
  --from-literal=CF_SPACE=space 

5. Deploymentの作成

deployment.yamlを以下のように設定します。

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cfcommand
  labels:
    app: cfcommand
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cfcommand
  template:
    metadata:
      labels:
        app: cfcommand
    spec:
      containers:
      - name: cfcommand
        image: docker.io/miyasuta/cfcommand:0.0.2
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        resources:
            limits:
              ephemeral-storage: 256M
              memory: 256M
              cpu: 100m
            requests:
              cpu: 100m
              ephemeral-storage: 256M
              memory: 256M
        env:
          - name: CF_USERNAME
            valueFrom:
              secretKeyRef:
                name: env-cfcommand
                key: CF_USERNAME
          - name: CF_PASSWORD
            valueFrom:
              secretKeyRef:
                name: env-cfcommand
                key: CF_PASSWORD
          - name: CF_API_URL
            valueFrom:
              secretKeyRef:
                name: env-cfcommand
                key: CF_API_URL
          - name: CF_ORG
            valueFrom:
              secretKeyRef:
                name: env-cfcommand
                key: CF_ORG 
          - name: CF_SPACE
            valueFrom:
              secretKeyRef:
                name: env-cfcommand
                key: CF_SPACE      
status: {}
      
---
apiVersion: v1
kind: Service
metadata:
  name: cfcommand
spec:
  selector:
    app: cfcommand
  ports:
  - port: 8080
    targetPort: 8080
    protocol: TCP

---

apiVersion: gateway.kyma-project.io/v1alpha1
kind: APIRule
metadata:
  name: cfcommand
spec:
  gateway: kyma-gateway.kyma-system.svc.cluster.local
  service:
    name: cfcommand
    port: 8080
    host: cfcommand
  rules:
    - path: /.*
      methods: ["GET", "POST"]
      accessStrategies:
        - handler: oauth2_introspection
          config: {}

ポイントは以下の2点です。

①シークレットを環境変数にバインドする
以下のセクションでenv-cfcommandというシークレットの各項目を、アプリケーションで使う環境変数にバインドしています。

    spec:
      containers:
        #...
        env:
          - name: CF_USERNAME
            valueFrom:
              secretKeyRef:
                name: env-cfcommand
                key: CF_USERNAME

参考:Define container environment variables using Secret data

②認証の設定
APIRuleの設定で、accessStrategies.handlerにoauth2_introspectionを設定します。これにより、APIにアクセスする際にKyma runtimeで作成したOAuthクライアントを使った認証が必要になります。

apiVersion: gateway.kyma-project.io/v1alpha1
kind: APIRule
metadata:
  name: cfcommand
spec:
    #...
  rules:
    #...
      accessStrategies:
        - handler: oauth2_introspection
          config: {}

OAuthクライアントの作成方法については、以下の記事をご参照ください。

※2023/3/15追記
OAuthクライアントを使用した認証はBTPのDestinationで使用することができなかった(認証エラーになる)ため、XSUAAを使用した認証に変更しました。

      accessStrategies:
        # - handler: oauth2_introspection
        #   config: {}
        - handler: jwt
          config: 
            jwks_urls:
            - https://f83f5860trial.authentication.us10.hana.ondemand.com/token_keys    

動作確認

Rest Clientを使ってAPIのテストを行います。一つ目のリクエストで認証用のトークンを取得し、二つ目のリクエストでCloud Foundry CLIを実行するAPIを呼び、ユーザにCloud Foundryのスペースロールを割り当てます。

@server=https://cfcommand.<クラスタードメイン>.kyma.ondemand.com
@oauthserver=https://oauth2.<クラスタードメイン>.kyma.ondemand.com
@user=OAuth2Clientのclient_id
@password=OAuth2Clientのclient_secret

### 1. Get Token
# @name client_credentials
POST {{oauthserver}}/oauth2/token
Authorization: Basic {{user}}:{{password}}
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

### 2. Add user to space
POST {{server}}/spaceuser
Content-Type: application/json
Authorization: Bearer {{client_credentials.response.body.access_token}}

{
    "user": "user",
    "role": "SpaceAuditor"
}

以下のような結果が返ってくれば成功です。
image.png

おわりに

これでCloud Foundryスペースへのユーザ登録がAPIでできるようになりました。次回はこのAPIをSAP Build Process Automationのフローに組み込んでいきます。

0
0
3

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
0
0