Oracle Functions (Fn) から、OCI SDKを実行してみた

# はじめに

Oracle Cloud が提供している FaaS である、Oracle Functions から OCI のSDKを実行する方法を書いていきます。
OCI には、現在のところ、4種類の言語でSDKが使用できるようです。

- Java
- Python
- Ruby
- Go



今回実装する内容は、Go言語のSDKを使って、Function から OCI の LoadBalancer 名前一覧を取得するものです。
GitHubにソースコードやDockerFileをアップロードしています。

https://github.com/Sugi275/fn-oci-lb-list



#SDK のクレデンシャル管理

## SDKを実行する方法

まずは、oci sdk を実行する方法を確認します。以下のGitHubに記載されています。
https://github.com/oracle/oci-go-sdk#configuring

2種類の実行方法があります。

1. oci 用の config ファイルを作成、RSA 秘密鍵を格納
   `~/.oci/config`

2. Interfaceを実装

   ```
   // ConfigurationProvider wraps information about the account owner
   type ConfigurationProvider interface {
      KeyProvider
      TenancyOCID() (string, error)
      UserOCID() (string, error)
      KeyFingerprint() (string, error)
      Region() (string, error)
   }
   ```



今回は、「2. Interfaceを実装」の方法を採用します。Oracle Functions は、コンテナイメージを使用して Function を実行するアーキテクチャとなっており、選択肢1では、コンテナイメージ内にRSA秘密鍵を格納する必要があることから、セキュリティ的に懸念があり、2を採用します。

2の選択肢では、Oracle Functions の環境変数に秘密鍵やUserOCID などの情報を指定することで、コンテナイメージ内にクレデンシャル情報を格納しない方法を取ります。



## ConfigurationProvider の Interface を実装

ConfigurationProvider Interface を、環境変数を利用する内容で実装します。なお、oci-go-sdk の common パッケージ配下にも、環境変数を使用するライブラリはありますが、秘密鍵そのものを環境変数として受け取る形ではないため、独自に実装するものとします。

参考：oci-go-sdk で環境変数を使用するライブラリ
https://github.com/oracle/oci-go-sdk/blob/master/common/configuration.go#L116



詳細は省略しますが、以下のGitHubのソースコードが、独自に実装した内容となります。oci-go-sdk/common で指定されている `ConfigurationProvider` Interface を実装している形になります。
https://github.com/Sugi275/fn-oci-lb-list/blob/master/src/ocilib/configration.go



# 実行方法

## GitHubからクローンして実行

Oracle Functions が実行できる環境で、自分が作成した Repository を Clone します

```
git clone https://github.com/Sugi275/fn-oci-lb-list.git
```



Oracle Functions にDeployします。なお、名前やコンテナイメージのバージョンなどが気になる場合は、適宜 func.yaml を変更してください。

```
fn --verbose deploy --app <fn application name> --no-cache
```



## 環境変数設定

Function に環境変数を設定します。OCIDなどは適宜自分の環境のものを指定します。



### bashの場合

```
# 秘密鍵をbase64でエンコードして、変数に格納
export OCI_PrivateRSAKeyEncyped=`base64 /home/ubuntu/.oci/oci_api_key.pem`

fn config func env-app oci-lb-list OCI_PrivateRSAKeyEncoded $OCI_PrivateRSAKeyEncoded
fn config func env-app oci-lb-list OCI_TenancyOCID "ocid1.tenancy.oc1..secret"
fn config func env-app oci-lb-list OCI_UserOCID "ocid1.user.oc1..secret"
fn config func env-app oci-lb-list OCI_KeyFingerprint "00:00:00:00:00:00:00:00:00:00:00:se:cr:et:da:yo"
fn config func env-app oci-lb-list OCI_Region "us-phoenix-1"
fn config func env-app oci-lb-list OCI_COMPARTMENT_ID "ocid1.tenancy.oc1..secret"

# 空白は設定しても反映されない。パスフレーズを指定する場合はコメントアウトを外して指定
# fn config func env-app oci-lb-list OCI_PrivateRSAKey_passphrase ""
```



### fishの場合

自分がfishをよく使っているので、fishの場合も記載します。

```
# fishでの環境変数設定。改行を有効にする
set IFS
set -x OCI_PrivateRSAKeyEncoded (base64 /home/ubuntu/.oci/oci_api_key.pem)
set IFS \n" "\t

fn config func env-app oci-lb-list OCI_PrivateRSAKeyEncoded $OCI_PrivateRSAKeyEncoded
fn config func env-app oci-lb-list OCI_TenancyOCID "ocid1.tenancy.oc1..secret"
fn config func env-app oci-lb-list OCI_UserOCID "ocid1.user.oc1..secret"
fn config func env-app oci-lb-list OCI_KeyFingerprint "00:00:00:00:00:00:00:00:00:00:00:se:cr:et:da:yo"
fn config func env-app oci-lb-list OCI_Region "us-phoenix-1"
fn config func env-app oci-lb-list OCI_COMPARTMENT_ID "ocid1.tenancy.oc1..secret"

# 空白は設定しても反映されない。パスフレーズを指定する場合はコメントアウトを外して指定
# fn config func env-app oci-lb-list OCI_PrivateRSAKey_passphrase ""
```



## function実行

functionの実行

```
fn --verbose invoke env-app oci-lb-list
```



実行例。LoadBalancerを2個作成しているため、2個の名前が表示されています。何も作っていない場合は、null と表示されます。

```
> fn --verbose invoke env-app oci-lb-list
{"message":["lb-20190220-0835","lb-20190221-0641"]}
```





# メモ ハマりポイント alpineからHTTPSアクセス

alpine linux をベースのコンテナイメージとしているが、コンテナからOCIのHTTPSエンドポイントをたたくためには、`ca-certificates` をinstallする必要があった。

```
FROM golang:1.11.5 as builder
WORKDIR /go/src/funcdir
COPY Gopkg.toml .
COPY src .
RUN go get -u github.com/golang/dep/cmd/dep && \
    dep ensure
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o func .

FROM alpine:3.9
WORKDIR /function/
RUN apk update && \
        apk add --no-cache ca-certificates <============= これ！
COPY --from=builder /go/src/funcdir/func .
ENTRYPOINT ["/function/func"]
```





# 参考URL

OCI の GO SDK
https://github.com/oracle/oci-go-sdk

SDK Config
https://docs.cloud.oracle.com/iaas/Content/API/Concepts/sdkconfig.htm

Example
https://github.com/oracle/oci-go-sdk/tree/master/example

Teraffrom oci
https://github.com/terraform-providers/terraform-provider-oci/blob/master/vendor/github.com/oracle/oci-go-sdk/common/configuration.go