プログラマ行進曲第二章

主にソフトウェア関連の技術をネタにした記事を執筆するためのブログ

2024年の抱負

2024年になって既に2週間が過ぎてしまって書くのに最適なタイミングを逸してしまった感がありますが、今年の抱負を考えてみようと思います。

今まで書いてきた抱負

意外と書いているものですね。書いた本人は何を書いたかほぼ忘れてますが。

2024年の抱負

IT系技能関連の目標

競技プログラミング系のコンテストに一度出場する

実は最近、競技プログラミングコンテストの過去問を少しずつ解いていく、なんてことをしています。

諸々思うところがあり、自分の実力アップのために最近ちょこちょこC++を学びつつ過去問を解いています。

過去問と言っても、atcoderのABCコンテストのA, Bを少しずつ解いているという感じなので、他の人に比べたらまだまだひよっこレベルのところでゼーハー言っているところです。

以下書籍を使って勉強しているのですが、自分にはちょうどいいレベル感の問題をリストアップしてくれているので助かっています。

ITはあまり関係ない目標

1年で3冊は本を読み、感想ブログを書く

パッと思いつかなかったので、前年の抱負からハードルを下げ、1年間に3冊本を読んで、それの感想をブログ記事にするというのを目標にしてみます。

…さて、ちゃんとできることやら…

達成度は計測しないが、やっていきたいこと

英語・中国語・ウクライナ語・スペイン語・アラビア語の学習を続けていく

実は去年からこれだけの言語の学習を続けています。

学ぶリソースは主に以下3つのリソースです。

なんだかんだで続けることができているので、このまま続けていこうと思います。

ウクライナ語が他の言語に比べて身についていないなー、と感じているので、何かしらテコ入れしたいところですね。

必要なサイトのみVPN経由でアクセスするOpenVPNの設定ファイルを生成する

VPN経由で作業をしないといけないケースがあります。

この時のクライアントソフトとしてよく使われているのがOpenVPN、またはOpenVPNベースのVPNクライアントです。AWS Client VPNとかそうですね。

こういうVPNを使うケースとしては、ある特定のサイトを不特定多数に公開しないようにすることがメインの目的として使われることが多いでしょう。

こういった場合、その特定のサイト以外は別にVPN経由でアクセスする必要は無いわけです。全ての通信をVPN経由にすると、よく分からない理由でネット接続の速度が落ちたりするといった経験もあり、必要なサイトにのみVPN経由でのアクセスをしたいと思っていました。

そんなことをしようと思って色々調べてやったことをまとめようと思います。

盛大に間違っているところもありそう*1なので、そんな箇所があったら誰か優しく指摘してください。

*1:特にOpenVPNやネットワークの理解が間違っているのが容易に想像できる

続きを読む

2023年の抱負

明けましておめでとうございます。

何か色々なことがあって空いてしまいましたが、今年は抱負を書こうと思います。

今まで書いてきた抱負

2020年に書いたっきりでその後放置してたんですね...まあ、時勢を考えたらむべなるかな、という気がしないでもありません。

それはまた別途書こうかなと言う気に今はなっています。

2023年の抱負

IT系技能関連の目標

2ヶ月に一度は技術系のネタでブログを更新する

書いたとおりですね。

仕事でAWSやKubernetesやAnsible(AWX含む)と色々と戯れていてエコシステム含めて知見が溜まっているのにそれをアウトプットとして残しておくのをサボっていて、あまりよろしくないよなあと思っていたので、あまり無理をせず、かといって少なすぎない程度の頻度でブログを残していこうかなという気分になっております。

ネタ自体はあっても外に出していかないと第三者に説明できないですしね。

直近パッと思いつくネタとしては以下の様なものがありますが、まあもっと手頃なネタにした方がいいんだろうなあ。

  • EKSの実運用ネタ
  • External Secrets Operator導入するのにすごい手間取った話
  • AWXを実運用してみて気づいたこと

ITはあまり関係ない目標

1年で4冊は本を読み、感想ブログを書く

2020年の記事でも同じ目標を立てていましたが、2020年はご存じの通り全世界的にドタバタがあって、目標を最終的に達成したのかどうか分からなくなっていたので、これはリベンジということで一つ。

読書習慣が崩壊した今だと1年で4冊も結構キツい気がしますが、目標は目標ということで。

達成度は計測しないが、やっていきたいこと

英語・中国語・アラビア語の学習を継続していく

主にduolingoでやっていきますが、アラビア語は東京外国語大学オープンアカデミーの講座で学んだことを復習したり、新しい講座を取ったりして定着できるといいかなと思ってますね。

そういえば東京外国語大学オープンアカデミーのことについてもブログでまとめようかなと思って幾星霜...

おまけ その1

特別お題「わたしの2022年・2023年にやりたいこと

と書いておくと新春お題キャンペーンに応募できるそうなので、ここに書いておきます。

おまけ その2

例年通り、初日の出を見に行ったので記念に写真撮ってきました。綺麗でよかったですね。

Untitled Untitled Untitled Untitled

今年は例年よりも初日の出を見に来ている人が多かったような気がしました。2倍はいたような気がしますね。

2020年の抱負

明けましておめでとうございます。

今年の抱負を書こうとしていたら、あっという間に正月休みを越えてしまいました。

もっと計画的に動かないといけないですね、と思った年初です。

今まで書いてきた抱負

今年の抱負 - プログラマ行進曲第二章

2014年の振り返りと今後やっていきたいこと - プログラマ行進曲第二章

2016年の抱負 - プログラマ行進曲第二章

2017年の抱負 - プログラマ行進曲第二章

2018年の抱負 - プログラマ行進曲第二章

2019年の抱負 - プログラマ行進曲第二章

2020年の抱負

IT系技能関連の目標

達成度を計測する目標としては今年も設定しないことにしました。

最初はここにも目標書いていたんですが、書いてみて見直したところ、多分達成できそうにないものだったので「達成度は計測しないが、やっていきたいこと」に移しました。

日和りました。

ITはあまり関係ない目標

1年で4冊は本を読み、感想ブログを書く

2019年も同じ目標を立ててやってみたところ、何とか達成できたので、今年も同じ量でやっていきたいと思います。

昨年挑戦してみて思ったのは、本を読むことよりも、読んだ本についてブログ記事を書く方が大分手間取るということが分かったので、4冊というのは冊数にすれば少ないですが、今の私の習慣からするとちょうどいい量なのかなとも思います。

まあ、今年もやっていきます。できるならもっと多くの本、それも技術書以外を読んでいきたいです。

1週間に1度は瞑想をする

実はこれはもう既に今年に入ってからやっていて、記録も取りつつ習慣化できつつあるので、記録残しとして1週間か2週間に1度ブログ記事にして証明するようにしようかなと思っています。

やっている内容としては以下の書籍、『サーチ・インサイド・ユアセルフ』の最初の簡単なやつ*1をやる感じですね。

以下に記載する事項を達成するためのキーとなる目標なので、習慣化して続けるようにしたいと思ってます。

達成度は計測しないが、やっていきたいこと

アルゴリズムとデータ構造の勉強を定期的に行う

これに関しては多くは語らないですが、自分の足りないところなので埋めていく感じでやっていきたいです。

達成度は計測しないですが、量の目安を記載すると、最低限以下の書籍を終わらせるところまではやるつもりです。量的には大分ハードルが低いですが。

オンラインジャッジではじめるC/C++プログラミング入門

オンラインジャッジではじめるC/C++プログラミング入門

  • 作者:渡部 有隆
  • 出版社/メーカー: マイナビ出版
  • 発売日: 2014/06/28
  • メディア: Kindle版

勿論、早く終わったら以下の書籍とか他のもの*2もやる予定です。

プログラミングコンテスト攻略のためのアルゴリズムとデータ構造

プログラミングコンテスト攻略のためのアルゴリズムとデータ構造

  • 作者:渡部 有隆
  • 出版社/メーカー: マイナビ出版
  • 発売日: 2015/01/30
  • メディア: Kindle版

まとめ

潰れない程度に頑張っていきます。

一つでもいい習慣が身につけることができるならいいのかな、なんて考えてます。

*1:2分間だけやる瞑想のこと

*2:LeetCodeや競技プログラミング的なもの

Argo CDのSSO設定をしてLDAPでログインできるようにしてみた

仕事でNomad環境からkubernetes環境への移行を進めていて、その流れでkubernetesのエコシステムを調べており、今はCI/CD周りを重点的に調べていて、その関係でArgo CDの調査をしています。

https://argoproj.github.io/argo-cd/

個人的にはkubernetesクラスタにデプロイしやすく、kustomizeとも連携してデプロイできたり、Web UIだけでなくCLIもちゃんとついていたりと、kubernetes用のCDシステムとして生まれただけあって、筋のいいソフトウェアだなと思いながら調査しています。

実運用にはいるときには認証・認可が問題になるので、最近はその辺りを調べているのですが、そこで中々パッとは分からなかったことがあるので覚え書きをメモして残そうと思い、記事を書きました。

Argo CDのログインをLDAPでやりたいとなったときにすること

私の職場ではあらゆる場面でLDAPを利用するようになっているので、Argo CDのSSOもLDAPでできるならやりたいところなので調べました。

Argo CD does not have any local users other than the built-in admin user. All other users are expected to login via SSO. There are two ways that SSO can be configured:

  • Bundled Dex OIDC provider - (以下略)

  • Existing OIDC provider - (以下略)

Argo CDの公式ドキュメントに書かれているように、Argo CD自体はadmin以外のユーザー管理をせず、他のユーザーを使いたい場合は組み込みのdexを使用するか、OktaやAuth0やOneLoginなど外部のOIDC Providerを使うかの2通りのやり方があります。

私のケースの場合、既にLDAPサーバーはあり、そのデータを使って管理をしたいので、組み込みのdexと連携させる必要があったのですが、Argo CDの方はgithub連携の例しか書いておらず、LDAPと連携したい場合は下記のdexのLDAP連携の記事と合わせて理解する必要があって、どうやっていいのかよく分かりませんでした。

https://github.com/dexidp/dex/blob/master/Documentation/connectors/ldap.md

結局最終的にどうやればいいのかよく分からなかったのですが、github連携の例を自分で試した後、「github連携の例で kubectl edit configmap argocd-cm -n argocd で変更しているConfigMapの値を、dexのLDAP connectorに記載されたフォーマットでLDAPの情報を書いてやればいいんだろうな」と分かったので試したところ、上手くいきました。

どんな値を入れたかというと、以下のような値です。LDAPサーバーのホストが yourldaphost 、LDAPサーバーが使用するportが 37685 、Argo CDのURLが https://localhost:8080 の時、以下のように書けば私のニーズは満たせました。

data:
  url: https://localhost:8080
  dex.config: |
    connectors:
    - type: ldap
      # Required field for connector id.
      id: ldap
      # Required field for connector name.
      name: LDAP
      config:
        host: yourldaphost.com:37685
        bindDN: cn=viewer,dc=yourldap,dc=com
        bindPW: <masked>
        usernamePrompt: LDAP Username
        userSearch:
          baseDN: dc=yourldap,dc=com
          username: uid
          idAttr: uid
          emailAttr: mail
          nameAttr: displayName

DexのLDAP connectorのドキュメントを見る限り、グループとかの設定も含めて細かく設定する場合は、LDAPの知識も必要になりそうな感じですが、単純なLDAP連携でいいならこんな感じでやればよさそうです。

LDAP連携だけだと権限はまだ設定していないので、,LDAPのユーザーやグループ毎に違う権限を設定したい場合はArgo CDのRBACの設定がおそらく必要なのでしょう。

引き続きArgo CDの使い方を調べていきたいと思います。

別のことを調べていたらGo言語のx/crypto/sshパッケージがOpenSSH形式のパスフレーズ付き秘密鍵にまだ対応できてないことに気づいたという話

業務中に調べていたら発見したことなのですが、発見した後調べてみたら既にクラスメソッドさんの記事でも触れられていたことだったのでまとめる意味あるかなと思いつつ、自分で調べて突き止めたことなので記録に残しておいた方が自分の実力の証明になるかと思い、久々に技術系の記事を書いてみます。

dev.classmethod.jp

dev.classmethod.jp

TL;DR

この問題に気づいたきっかけ

もともとgolangのアプリを書いて気づいたわけではなく、KubernetesのCI/CD周りのエコシステムを調べている中でArgoCDの調査をしており、ArgoCDにSSH private keyを使ってgithub等のprivate repositoryを登録するのを試していたところ、ArgoCDのCLIがエラーを出したので、まずArgoCDのrepositoryにissue登録をしました。

github.com

issueにも書きましたが、出たエラーはこんな感じです。

$ argocd repo add git@github.com:<my private repository> --ssh-private-key-path ~/.ssh/id_rsa
FATA[0000] ssh: cannot decode encrypted private keys

そしてissue登録をした後にdelveでデバッグをしながらArgoCDのソースコードを見たところ、まずこの箇所で引っかかっていることが分かり、step inしながら調べたところ、ssh.ParsePrivateKey関数にしか対応していないことが分かったので、単にArgoCDの問題かと思って一旦放置していました。

ただ、少し経った後「別に技術調査中なんだから、雑にこの箇所をssh.ParsePrivateKeyWithPassphrase関数を使うように書き換えたCLIをビルドして試すのはありなんじゃないか?」と思ったので、雑に書き直した後ビルドして試したところ、またエラーが出てきて「あれ?」と問題に気づいたという流れです。

x/crypto/sshパッケージ自体に問題があると確信するためにした検証の仕方

上記の流れでArgoCDのCLIの挙動をdelveを使って追ったり、x/crypto/sshパッケージのソースコードを読んだりして、細かい検証をする前にx/crypto/sshパッケージ自体に問題がありそうだと思ってはいたのですが、VSCode経由でArgoCDのCLIをdelveでデバッグしていたときの変数の中身の表示がおかしかったりして、本当にx/crypto/sshパッケージの問題なのか他者に証明しづらかったので、ssh.ParsePrivateKeyWithPassphrase関数の挙動がおかしいことを示すコードをgistに残し、挙動を確かめたところ、やはりssh.ParsePrivateKeyWithPassphrase関数自体が手元のssh private key(パスフレーズ付き)をパース出来ないことが分かりました。

確認するのに使ったコードなどは上記のgistに全て書いているのですが、リンク先に飛ぶのも面倒なので以下に同内容のコードを説明付きで書いていきます。

使用したパスフレーズ付き秘密鍵を生成したOpenSSHのバージョン、秘密鍵の状態、Go言語のバージョンは以下の通りです。

$ ssh -V
OpenSSH_7.9p1, LibreSSL 2.7.3

$ ssh-keygen -l -f ~/.ssh/id_rsa
2048 SHA256:/<masked> taku@altair.local (RSA)

$ go version
go version go1.12.6 darwin/amd64

この環境で以下のGoのコードを実行します。

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "os"

    "golang.org/x/crypto/ssh"
)

func main() {
    sshPrivateKeyPath := os.Args[1]
    keyData, err := ioutil.ReadFile(sshPrivateKeyPath)
    if err != nil {
        log.Fatal(err)
    }
    signer, err := ssh.ParsePrivateKey([]byte(keyData))
    if err == nil {
        fmt.Println(signer)
        os.Exit(0)
    }

    passPhrase := os.Getenv("PASSPHRASE")
    if passPhrase == "" {
        fmt.Println("Please configure `PASSPHRASE` environment variable for your passphrase")
        os.Exit(1)
    }

    signer, err = ssh.ParsePrivateKeyWithPassphrase(keyData, []byte(passPhrase))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Parsed private key with passphrase!!")
    fmt.Println(signer)
}

雑なコードですが、PASSPHRASE環境変数が正しく設定されていて、実行時にパスフレーズ付き秘密鍵のパスを指定していればssh.ParsePrivateKeyWithPassphrase関数を実行するようになっていて、signerが表示されるのが期待する動作というコードです。

これで意図通りに動くのか以下のように確かめました。

# ~/.ssh/id_rsa がパスフレーズが無い秘密鍵の時
$ go run main.go ~/.ssh/id_rsa
&{0xc0000ac120 0xc0000ac120}
# 事前にファイルを使って export PASSPHRASE="<~/.ssh/id_rsa のパスフレーズ>" と下準備して、パスフレーズ付き秘密鍵を使用する時
$ go run main.go ~/.ssh/id_rsa
2019/07/11 23:25:03 ssh: cannot decode encrypted private keys
exit status 1

上記のように、パスフレーズ付き秘密鍵の時にはエラーとなり、期待通りに動いていないことが分かりました。

このエラーが「SSH private key側の問題」なのか、「ssh.ParsePrivateKeyWithPassphrase関数の問題」なのかを調べるため、delveを使って上記Goのソースコード実行時の状態を見たところ、以下の箇所でエラーが出ているところまで突き止めました。

詳しくはgistに残したコメントを参照して欲しいのですが、ここまで調べた段階で個人的には「エラーハンドリングが甘い(=ssh.ParsePrivateKeyWithPassphrase関数の問題)のでは?」とほぼ確信はしていたのですが、普段扱っているわけではないgolangの話だったので、社内Slackの #golang チャンネルにgistのコードを添付して質問して他の人にもチェックしてもらったところ、やはりssh.ParsePrivateKeyWithPassphrase関数の問題だと言われました。

自分で調べているときにも見つけてはいましたが、上記Slackチャンネルでも「以下issueに関係ある話なのでは?」と指摘され、ほぼ間違いなくx/crypto/sshパッケージ自体の問題だと判明。

github.com

何が問題だったかというと、OpenSSH 7.8からssh-keygenで生成される秘密鍵のフォーマットがOpenSSH形式になったのに、x/crypto/sshパッケージではまだそのOpenSSH形式のフォーマットのパスフレーズ付き秘密鍵をサポートできていなかったことがこのエラーを引き起こしていたのです。

自分自身ではこのOpenSSHのバージョン違いによる秘密鍵のフォーマットの差には気がつかなかったので、教えてもらえたことで最終的な原因に気がつけてよかったです。

教えてもらったときに参考に貼ってもらった記事は以下のものがありました。

qiita.com

検証後に気づいたことと感想

こういう風に色々調べきった後に改めて調べ直していたら、本記事の頭に書いたように既にクラスメソッドさんの記事でこの問題に言及されていたことに気づきました。

最初の方で見つけられていれば原因特定が早くなったと思いますが、今回自力で大半の原因を特定でき、分からない所は分かりそうな人に質問して特定するといったフローを実際に実行でき、経験が積めたので、今回はこれでよかったのかなと思います。

余談になりますが、このOpenSSH形式の秘密鍵をgolangで扱いたい場合は、x/crypto/sshに関するissueでコメントされているように、ScaleFT/sshkeysという3rd party製パッケージを使えば出来るみたいです。試したことはないので保証は出来ませんが。

golangの場合、delve(+VSCode)によるデバッグが非常に強力だというのも実感しました。またgolangを使ってデバッグをすることになったら今回の経験を活かしたいと思います。

*1:使ったことがないので憶測です

Ansibleのwhen節で複数行に複数の条件を書くやり方に迷ったので調べた

結論から書くと、以下のように書ける。

when: >
  ('redhat-stable' in repo_url) or
  ('redhat-stable' in repo_key_url) or
  ('redhat-stable' in package_url)

ポイントは以下の通り。以下の説明は細かい検証はしていない or メモしていないので細かい部分で間違っているかもしれないです。

> とか | を使って複数行に書けるようになる

上記のwhenの場合、条件をそれぞれカッコでくくる

そうしないとエラーになった。原因までは調べてない。

when内では変数はそのまま、文字列はクオートでくくる

repo_url がansibleの変数(中身は文字列)の時、 'redhat-stable' in repo_url は問題ないが、 redhat-stable in repo_url はエラーになるということ。

Ansible難しいなと思ったところ

yamlファイル内に書くとき、「こう書きたい」と思った表現が書けるかどうか、以下の知識を持っていないと完全に判断が付けられないところ。

  • Ansible固有の知識
    • when節に書ける法則 etc.
  • Jinja2の知識
  • YAMLの仕様・知識