セキュリティ系の勉強・その他開発メモとか雑談. Twitter, ブログカテゴリ一覧
本ブログはあくまでセキュリティに関する情報共有の一環として作成したものであり,公開されているシステム等に許可なく実行するなど、違法な行為を助長するものではありません.

go1.18を使ったときに、golangci-lintのtypecheckのエラーが出たり、go generateがこけた

golangci-lintのtypecheckのエラー

go.modで、go1.16が指定されているプロジェクトで、手元のgoのバージョンを1.18.2にしてgolangci-lintを実行したときに、今まで出ていなかったエラーが発生しました。こんな感じ

...net/http/httptest (-: could not load export data: no export data for "net/http/httptest") (typecheck)
    "net/http/httptest"
    ^
k8sapiserver/k8sapiserver.go:23:13: could not import...load export data: no export data for "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes") (typecheck)
    authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
               ^...
...

go1.16.15go.17.10では、上記のエラーは発生していませんでした。

対処

golangci-lintのバージョンを最新に上げました。(ちょうど別件でgo.modに記載のバージョンも上げたので念のため記載しておきます。)

# go.mod

- go 1.16
+ go 1.17

-   github.com/golangci/golangci-lint v1.41.1
+   github.com/golangci/golangci-lint v1.46.2

上記の対応により、手元のgoバージョンgo1.18.2で、先のエラーは発生しなくなりました。

go generateがこけた

上記の続きで、go1.18.2を使ったときにgo generateを実行したときに以下のエラーが発生しました。

go generate ./...
prog.go:12:2: cannot find package "." in:
        /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model
Please reference the steps in the README to fix this error:
        https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: cannot find package "." in:
        /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model
Please reference the steps in the README to fix this error:
        https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: no required module provides package github.com/golang/mock/mockgen/model: go.mod file not found in current directory or any parent directory; see 'go help modules'
prog.go:14:2: no required module provides package sigs.k8s.io/kube-scheduler-simulator/simulator/export: go.mod file not found in current directory or any parent directory; see 'go help modules'
2022/07/10 14:41:06 Loading input failed: exit status 1
export/export.go:3: running "mockgen": exit status 1
prog.go:12:2: cannot find package "." in:
        /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model
Please reference the steps in the README to fix this error:
        https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: cannot find package "." in:
        /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model
Please reference the steps in the README to fix this error:
        https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: no required module provides package github.com/golang/mock/mockgen/model: go.mod file not found in current directory or any parent directory; see 'go help modules'
prog.go:14:2: no required module provides package sigs.k8s.io/kube-scheduler-simulator/simulator/node: go.mod file not found in current directory or any parent directory; see 'go help modules'
2022/07/10 14:41:07 Loading input failed: exit status 1
node/node.go:3: running "mockgen": exit status 1
prog.go:12:2: cannot find package "." in:
        /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model
Please reference the steps in the README to fix this error:
        https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: cannot find package "." in:
        /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model
Please reference the steps in the README to fix this error:
        https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: no required module provides package github.com/golang/mock/mockgen/model: go.mod file not found in current directory or any parent directory; see 'go help modules'
prog.go:14:2: no required module provides package sigs.k8s.io/kube-scheduler-simulator/simulator/replicateexistingcluster: go.mod file not found in current directory or any parent directory; see 'go help modules'
2022/07/10 14:41:08 Loading input failed: exit status 1
replicateexistingcluster/replicateexistingcluster.go:3: running "mockgen": exit status 1
prog.go:12:2: cannot find package "." in:
        /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model
Please reference the steps in the README to fix this error:
        https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: cannot find package "." in:
        /workspace/kube-scheduler-simulator/simulator/vendor/github.com/golang/mock/mockgen/model
Please reference the steps in the README to fix this error:
        https://github.com/golang/mock#reflect-vendoring-error.prog.go:12:2: no required module provides package github.com/golang/mock/mockgen/model: go.mod file not found in current directory or any parent directory; see 'go help modules'
prog.go:14:2: no required module provides package sigs.k8s.io/kube-scheduler-simulator/simulator/scheduler/plugin: go.mod file not found in current directory or any parent directory; see 'go help modules'
2022/07/10 14:41:09 Loading input failed: exit status 1
scheduler/plugin/wrappedplugin.go:13: running "mockgen": exit status 1
make: *** [Makefile:3: generate] Error 1

go1.16.15を使用していたときは発生していませんでしたが、こちらgo1.18.2を使用し始めたときに発生するようになりました。

対処

ここにある2つのうちのどちらかで対処可能です。

dev.to

例えば以下のように修正します。

- //go:generate mockgen -destination=./mock_$GOPACKAGE/pod.go . PodService
+ //go:generate mockgen --build_flags=--mod=mod -destination=./mock_$GOPACKAGE/pod.go . PodService

k8s resource watchする

あらまし

PodとかNodeとかリソースの更新を監視したかったです。 (消すコードをぱぱっと持ってきたのでもしかしたら変な部分があるかもしれません。雰囲気でも伝われば幸いです)

雑にやったこと

Server pushってやつで、クライアント側ではfetchで呼び出してデータを受け取る感じです。(streamってやつかと)
まず、echoを使っていてこのメソッドをハンドラとして公開するイメージです。

func (h *WatcherHandler) WatchResources(c echo.Context) error {
    ctx := c.Request().Context()
 
    c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
    c.Response().WriteHeader(http.StatusOK)
    // Start to watch and do server push
    err := h.service.WatchResources(ctx, c.Response())

    if err != nil {
        klog.Errorf("closed to watch resources: %+v", err)
        return echo.NewHTTPError(http.StatusInternalServerError)
    }
    return nil
}

肝心のwatchする部分はこんな感じ。もう消すコードだったのでちょっと雑に貼ります、、

type ResponseStream interface {
    io.Writer
    http.Flusher
}

func (s *Service) WatchResources(ctx context.Context, stream ResponseStream) error {
  podsWatcher := cache.NewListWatchFromClient(s.client.CoreV1().RESTClient(), string(Pods), corev1.NamespaceAll, fields.Everything())
    _, podsController := cache.NewInformer(podsWatcher, &corev1.Pod{}, 0, createResourceEventHandlerFuncs(watchEventQ, Pods))
  go podsController.Run(ctx.Done())
  <-ctx.Done()
  return xerrors.Errorf("terminated to watch: %v", ctx.Err())
}

func createResourceEventHandlerFuncs(weq *watchEventQueue, r resourceKind) cache.ResourceEventHandlerFuncs {
    return cache.ResourceEventHandlerFuncs{
        AddFunc:    AddedEventHandler(weq, r),
        UpdateFunc: ModifiedEventHandler(weq, r),
        DeleteFunc: DeletedEventHandler(weq, r),
    }
}

func AddedEventHandler(weq *watchEventQueue, r resourceKind) func(obj interface{}) {
    return func(obj interface{}) {
        // ここで受け取ったイベントを処理する
    }
}
...

server pushする部分はこんな感じ

func watchAndFlushQueue(obj interface{}, stream ResponseStream) error {
    enc := json.NewEncoder(stream)
    for {
        if weq.IsEmpty() {
            continue
        }
        if err := enc.Encode(obj); err != nil {
            return xerrors.Errorf("encode a WatchEvent in the queue: %w", err)
        }
        stream.Flush() // これでクライアントにpushされる
    }
}

このコードを使わなかった訳

cache.NewInformerの部分では「list呼び出し→watch監視開始」と実行されます。これは、resourceVersionフィールドの値をlistで取得してwatchでそれを使うことで、無駄な昔の情報をwatchで取得しないようにとかに使います。またこのメソッドで生成されるやつは、watch接続が途切れた場合に、自動で復帰もしてくれる(はず)の優しいやつです。
それが故に、この一連の動作を再度呼び出した時に再度listから実行してしまうことが予想されます。これは今回の私の目的にあっていませんでした。また、resourceVersionフィールドは外側から指定することができず完全に隠されているので、クライアント側からresourceVersionを指定して、好きな位置から情報取得をすることができません。
これらにより、便利ではあるんですが、今回は上記の実装は諦めました。

Nuxt.js runtimeConfigの値がundefinedになる

あらまし

コンテナ化して、docker-composenuxtjs製のアプリケーションを実行しようとしています。 その際、nuxtjsの機能であるruntimeConfigを使用して、ランタイムで環境変数を渡そうとした時に、上手く値が渡せずundefinedが渡されていました。

症状

例えば、以下のように環境変数を読ませようとします。

# nuxt.config.js
publicRuntimeConfig: { baseURL: process.env.BASE_URL || "https://localhost:3000" },

これをどうにか呼び出した時にundefinedが返ってきます。

const baseURL = context.$config.baseURL  ## => undefined

Dockerfileはこんな感じ

FROM node:16-alpine AS deps

RUN apk update && \
    apk upgrade && \
    apk add --no-cache make gcc g++ py-pip

WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

FROM node:16-alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN yarn build && yarn install --production --ignore-scripts --prefer-offline

FROM node:16-alpine AS runner
WORKDIR /app

ENV NODE_ENV production
ENV NUXT_TELEMETRY_DISABLED 1
ENV HOST_ENV production
ENV BASE_URL http://localhost:1212
ENV KUBE_API_SERVER_URL http://localhost:3131

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nuxtjs -u 1001

COPY --from=builder ./app/package.json ./
COPY --from=builder ./app/node_modules ./node_modules/
COPY --from=builder ./app/.nuxt ./.nuxt/
COPY --from=builder ./app/static ./static/

USER nuxtjs

EXPOSE 3000

CMD ["yarn", "start"]

原因:実行環境にnuxt.config.jsをコピーしていない

上記のDockerfileはビルドと実行を別環境で行なっています。実行環境にビルドしたものを移す際に、nuxt.config.jsを移していませんでした。おそらく、runtimeConfigは実行時にnuxt.config.jsを参照してよしなにするのだと思います。
次のようにnuxt.config.jsをコピーする操作を追加して解決します。

...
COPY --from=builder /app/nuxt.config.js ./   ## Add 
COPY --from=builder ./app/package.json ./
COPY --from=builder ./app/node_modules ./node_modules/
COPY --from=builder ./app/.nuxt ./.nuxt/
COPY --from=builder ./app/static ./static/

USER nuxtjs

EXPOSE 3000

CMD ["yarn", "start"]

よく考えると、環境変数が上手く読み込めていないのであれば、undefinedではなく、デフォルト値として設定したhttps://localhost:3000が入っているはずなので、この辺りで気がつけるといいかも。

参考

これに助けられました。

github.com

nuxtjsruntimeConfigについて

zenn.dev

原因の元となったファイル

github.com

kubernetes ScalarResources

v.1.23で確認

ScalarResources

このScalarResourcesってなんなのって思いました。

// pkg/scheduler/framework/types.go#L410-L419より
type Resource struct {
    MilliCPU         int64
    Memory           int64
    EphemeralStorage int64
    // We store allowedPodNumber (which is Node.Status.Allocatable.Pods().Value())
    // explicitly as int, to avoid conversions and improve performance.
    AllowedPodNumber int
    // ScalarResources
    ScalarResources map[v1.ResourceName]int64
}

source code

k8sのdocsでもあまりヒットしなかったので、僕の調べた結果の予想をちょろっと書いておきます。

結果的には構造体に定義されたCPUMemoryEphemeralStorage以外のリソースを指すんじゃないかと思います。どういうことかというと、例えばメモリの場合こんな感じで書きます。(メモリリソース割り当てページより)

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-ctr
    image: polinux/stress
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

この、resources.requestsresources.limitsに映えてるmemoryの値が、Resource構造体のMemoryに格納されるんじゃないかと思います。例えばEphemeralStorageならこんな感じ

じゃあ、ScalarResourcesはというと、例えば拡張リソース

apiVersion: v1
kind: Pod
metadata:
  name: extended-resource-demo
spec:
  containers:
  - name: extended-resource-demo-ctr
    image: nginx
    resources:
      requests:
        example.com/dongle: 3
      limits:
        example.com/dongle: 3

リソース名にexample.com/dongleといった感じで各自のドメイン名が入るので、memoryのように単一で表記できない。Huge pageもおそらく名前が可変(定義する名前が変わる)なので、ScalarResourcesに格納しておくといった感じかと思う。

pkg/scheduler/util/utils.goに、IsScalarResourceNameという関数があり、そこでリソース名から判定を行える。この実装を見てみると、上記の拡張リソースHuge pageは、ScalarResourcesに含まれると考えられる。

Scalarという単語に馴染みがなかったので不安ですが、言葉の定義として文字列が含まれるようなので、ScalarResourcesという名前も一応腑に落ちた気がします。

合っているか分からないので、マサカリ歓迎します。

CTF MySQLとか「''-sleep(1)」に関して

あらまし

ここのwriteupで次のようなSQL文がある。

select * from login where username=''-sleep(1);

https://blog.bi0s.in/2019/10/16/Web/inctfi19-web-writeups/


この結果、loginテーブルの内容が全て取得できているロジックがいまいちわからなくて調べた。

準備

create table Test(id integer, title varchar(100));
insert into Test(id, title) values(1, "Hello");
insert into Test(id, title) values(2, "foo");
insert into Test(id, title) values(3, "bar");

-は何

演算子としての-正規表現中に出現する-がある。任意の文字がマッチするようになるのかと思ったけれど、恐らく演算している。

select * from Test where title='false'                    // 結果なし
select * from Test where title=''-false;                 // テーブル出力
select * from Test where title=''-true;                  // 結果なし
select * from Test where title=''-0;                       // テーブル出力
select * from Test where title='aaaa'-false;         // テーブル出力

sleep0が帰ってくるはず。上の結果から、booleanの値が関係してそう。

false 0 減算など

SELECT '' IS false;                   // 1
SELECT 0 IS false;                   // 1
SELECT 0 IS true;                     // 0
SELECT ''-0 IS false;               // 1
SELECT 'aaa'-false IS false;   // 1
SELECT 'aaa'-0 IS false;         // 1

上の結果から、多分演算が型の違いか何かで失敗してfalseが返ってることがわかる。

where username=false;?

select * from Test where title=false;         // テーブル出力
select * from Test where title=true;          // 結果なし

''-sleep(1)は演算失敗してfalseが返ってくることで、全テーブルが得られていたと推測できる。また、先にsleep(1)が評価されて、sleepが実行されてるのも面白いですね。