takafumi blog

日々の勉強メモ

aws cliのMFA(多要素認証)によるAccessDeniedExceptionの対応

どういう状態か

何のコマンドでも以下のようになる。

$ aws lambda list-functions 
An error occurred (AccessDeniedException) when calling the ListFunctions operation: User: arn:aws:iam::111111111111:mfa/username is not authorized to perform: lambda:ListFunctions on resource: * with an explicit deny

確認したのは

  • IAMに権限はある
  • ~/.aws/{credentials,config} はある

原因

MFA(多要素認証)エラーだった

調べ方

IAM Policy Simulatorコンソールが公式に用意されているので、こちらで調べる
(iam policyはaws iam simulate-principal-policyでも通常調べる事もできるが、この場合は同じくAccessDeniedExceptionになる)

https://policysim.aws.amazon.com/

こんな感じで機能、使いたいポリシーを選択、Run Simulationを押すと詳細な原因が表示されるAccessDeniedExceptionになる)

f:id:takafumi-s:20210802233822p:plain

結果

        {
            "Sid": "DenyAllExceptListedIfNoMFA",
            "Effect": "Deny",
            "NotAction": [
                "iam:CreateVirtualMFADevice",
                "iam:EnableMFADevice",
                "iam:GetUser",
                "iam:ListMFADevices",
                "iam:ListVirtualMFADevices",
                "iam:ResyncMFADevice",
                "iam:ChangePassword",
                "iam:GetAccountPasswordPolicy",
                "sts:GetSessionToken"
            ],
            "Resource": "*",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "false"
                }
            }
        }

この結果を調べると以下のページから

AWS: Allows MFA-authenticated IAM users to manage their own MFA device on the My Security Credentials page - AWS Identity and Access Management

The DenyAllExceptListedIfNoMFA statement denies access to every action in all AWS services, except a few listed actions, but only if the user is not signed in with MFA.

MFAで認証していないとエラーだとわかる。

対応方法

以下のサイトを参照に一時認証情報を作成する

aws.amazon.com

aws sts get-session-token --serial-number arn:aws:iam::111111111111:mfa/username --token-code 【MFAトークン】
{
    "Credentials": {
        "AccessKeyId": "AAA",
         "SecretAccessKey": "bbb",
         "SessionToken": "ccc",
         "Expiration": "2021-08-03T03:24:32+00:00"
     }
}

これを ~/.aws/credentialsへ設定

[mfa]
aws_access_key_id = AAA
aws_secret_access_key = bbb

~/.aws/config 側へregionなども設定しておく

そして最初のコマンドを --profile 付きでたたくと結果が表示されるようになる

$ aws lambda list-functions --profile mfa

{
    "Functions": [

...省略

MFAの設定を簡略化する

この辺の設定をもう少し簡単に、またsessionを自動更新するには以下のツールを使う

github.com

詳しくはREADME.mdにあるが簡単にメモしておくと

  1. ~/.aws/credentials[default] -> [default-long-term] に変更
  2. コマンドを実行して、あとは支持に従ってmfaコードを入力
$ aws-mfa --duration 1800 arn:aws:iam::111111111111:mfa/username
INFO - Validating credentials for profile: default
WARNING - Your existing credentials are missing or invalid, obtaining new credentials.
Enter AWS MFA code for device [arn:aws:iam::111111111111:mfa/username] (renewing for 1800 seconds):
INFO - Fetching Credentials - Profile: default, Duration: 1800
INFO - Success! Your credentials will expire in 1800 seconds at: 2021-08-07 14:13:08+00:00   

これで--profile なしでMFA有りのaws cliを使えるようになり、指定の --duration で自動でsessionを更新してくれるようになる

gpg: keyserver receive failed: Server indicated a failure

Ubuntu 20.04.2 LTS

gpgが使うhkpプロトコルはport 11371 を使う。

なので

gpg: keyserver receive failed: Server indicated a failure

このエラーは大概portを変えれば解決することが多い(と思う)

# github-cliのpgp鍵取得
# https://github.com/cli/cli/blob/trunk/docs/install_linux.md


sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key C99B11DEB97541F0

ちなみにPGPは、Pretty Good Privacyの略。センスがいい。

Slackのチャネル作成+ユーザー(&グループ)複数をまとめて招待できるコマンドをGAS+typescriptで作った

typescript 4.2.3

Slackで新チャンネルを作るときに、ユーザーもまとめて招待できるコマンドを作成してみた。 チャンネル名はある程度固定で使う事を想定した。

また(だいぶ前から) claspがtypescriptをサポートしていたので書いてみた

・・・が割とコードが膨大になったので、結局webpackしてアップロードするようにしたので、あまりtypescriptのサポートは関係なくなってしまった

github.com

最初はペラっと1,2ファイルのつもりだったのをガリガリ拡張したので、ちょっと雑になってしまった

コードはgithubを見てもらうとして、作っている途中に引っかかったところを書いてみる。

Slack

  • Q: slash command打ったらdispatch_failedと出る
    • A: commandに設定したURLが200 OKを返してない
    • A: curlなどで確認してみる。3xxでもNG
    • A: AppsScriptでデプロイを新しく作り直してみる
  • Q: slash command打ったらtimeout が返ってくる
    • A: 3000ms以上だとそうなる。slack仕様。
    • A: ロジックを工夫する。api何度も叩くようなのは非同期実行する
      • 今回はユーザーデータ、グループデータはtriggerで別に取得するようにした
      • 多分GASだと非同期にしてもrootなメソッド(これだとdoPost)は終わらないぽいので非同期できない
  • Q: ユーザーグループ名がリクエストボディからうまく取得できない
    • A: グループは<!subteam^S0AAAAA0A|@usergroup_name>のようなテキストで入ってくるので、パースする必要がある

GAS

  • Q: clasp createで作ったAppsScriptだとGCPプロジェクトを変更できない事がある
    • A: GAS側で新規プロジェクトで作る
  • Q: clasp pushでエラーになる
  • Q: doPostのログが確認できない
    • A: GCPプロジェクトと紐づけて、ロギングを見る必要がある
    • A: ロギングはテストのまま使うにはテストユーザーを登録する必要がある
  • Q: GASからHTTPリクエストできない
    • A: http requestはUrlFetchAppを使う
      • scope https://www.googleapis.com/auth/script.external_request を許可する必要がある
    • A: webpackすれば他のnpmも使えるかもしれないが未検証
  • Q: GAS実行時の権限設定でエラー表示になる
    • A: GCPプロジェクトのOAuth同意画面で公開ステータスが本番環境になっている必要がある
    • A: テスト ならテストユーザーに登録する

GAS written with typescript

  • Q: import * as X from './xxx' エイリアスが読めない
    • A: GASではすべてのクラスがフラットな状態で存在するので実際の名前を全部指定する必要がある
    • A: また同じ名前のexportは競合するので使えない
    • A: webpackする
  • Q: eslint, tsc, babel, webpack全部通るのにアップロードするとエラーになる
    • A: ときどきある。諦めて書きかえる
      • ts2gasをきちんと見ればわかるかも

その他

  • Q: GAS webappについて
    • A: webappとかapiデバッグに時間がかかる
      • ローカルである程度変換してもclaspで変換されたものが動作するかはデプロイするまで分からない
    • A: 1,2ファイルで終わるシンプルなもの、spredsheetやdrive使う場合以外はサーバ立てた方が楽に思う

【Scala】giter8でプロジェクトのテンプレートを作る

環境   Scala 2.13.0

[1] giter8のテンプレートを用意

$ sbt new foundweekends/giter8.g8

[info] Loading settings for project global-plugins from metals.sbt ...
[info] Loading global plugins from /home/takafumi/.sbt/1.0/plugins
[info] Set current project to a (in build file:/home/takafumi/A/)
[info] Set current project to a (in build file:/home/takafumi/A/)

Creates a Giter8 project template. 

name [My Te mplate Project]: scala-template
giter8_version [0.12.0-M2]: 
sbt_version [1.2.8]: 1.3.0

Template applied in /path/to/dir/scala-template

[2] src/main/g8/ の下にテンプレートにしたいプロジェクトを追加

[3] src/main/g8/default.properties にテンプレートで使えるプロパティを定義できる

// default.properties
name=scala-template
version=1.0
scala_version=1.3.0
sbt_version=1.2.8
// e.g. build.sbt
name = "$name$"
scalaVersion := "$scala_version$"

[4] ローカルでテストしたいときは

$ sbt new file:///path/to/dir/scala-template

[5] githubにpushしたら

$ sbt new repository/scala-template

で使えるようになる

www.foundweekends.org

【Rust】【Vim】LSPの導入

  • 環境
    • archlinux 5.0.9-arch1-1-ARCH
    • rust 1.34.1
    • neovim 0.3.5

rust

rls(Rust Language Server)

https://github.com/rust-lang/rls

rustup component add rls
rustup component add rust-analysis
rustup component add rust-src

neovim

dein + LanguageClient-neovim

https://github.com/autozimu/LanguageClient-neovim

"
" lsp.toml
"
[[plugins]]
repo        = 'autozimu/LanguageClient-neovim'
rev         = 'next'
build       = 'bash install.sh'
hook_add = '''
   let g:LanguageClient_autoStart = 1  " LanguageServerを自動起動する

   " 言語毎のLSPを設定
   let g:LanguageClient_serverCommands = {
      \ 'rust': ['rustup', 'run', 'stable', 'rls'],
   \ }

   augroup LanguageClient_config
      autocmd!
      autocmd User LanguageClientStarted setlocal signcolumn=yes
      autocmd User LanguageClientStopped setlocal signcolumn=auto
   augroup END

   nnoremap [lsp] <Nop>
   nmap <Space>l [lsp]

   nnoremap [lsp]h :call LanguageClient_textDocument_hover()<CR>
   nnoremap [lsp]d :call LanguageClient_textDocument_definition()<CR>
   nnoremap [lsp]r :call LanguageClient_textDocument_rename()<CR>
   nnoremap [lsp]f :call LanguageClient_textDocument_formatting()<CR>
   '''

init.vimなどで以下のコマンドで読み込ませる

call dein#load_toml(s:toml_dir . '/lsp.toml', {'lazy': 0})

遅延読み込み('lazy':1)だとLanguageServerが起動ないので注意(大分長い事嵌った)

【Rust】導入覚書

  • 環境
    • archlinux 5.0.9-arch1-1-ARCH
    • rust 1.34.1
    • neovim 0.3.5

rust

binary

https://rustup.rs/

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

echo 'source $HOME/.cargo/env' >> ~/.zshrc

rustc -V
rustc 1.34.1 (fc50f328b 2019-04-24)

cargo -V
cargo 1.34.0 (6789d8a0a 2019-04-01)

source

補完系で必要になる

rustup component add rust-src

rustup update

echo 'export RUST_SRC_PATH="$(rustc --print sysroot)/lib/rustlib/src/rust/src"' >> ~/.zshrc

component, tool, etc

formatter

https://github.com/rust-lang/rustfmt

rustup component add rustfmt

linter

https://github.com/rust-lang/rust-clippy

rustup component add clippy

watcher

https://github.com/passcod/cargo-watch

cargo install cargo-watch

Cargo.toml editor

https://github.com/killercup/cargo-edit

cargo install cargo-edit

code completion

設定面倒くなければ rls使ったほうが良いかも

takafumi-s.hatenablog.com

https://github.com/racer-rust/racer

## From 2.1, racer needs nightly rust
rustup toolchain add nightly

cargo +nightly install racer

vim

dein.vimでplugin管理しているならなら以下をtomlファイルに追加し、UpdateRemotePlugins

rust.vim

detection, syntax highlighting, formatting

https://github.com/racer-rust/vim-racer

[[plugins]]
repo = 'rust-lang/rust.vim'
on_ft = 'rust'
hook_source = '''
    let g:rustfmt_autosave = 1
'''

vim-racer

vimでracerを使うplugin

https://github.com/racer-rust/vim-racer

repo = 'racer-rust/vim-racer'
on_ft = 'rust'
hook_source = '''
    " racerバイナリ
    let g:racer_cmd = "~/.cargo/bin/racer"
    " rustソースコードパス
    let $RUST_SRC_PATH="~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src"

    let g:racer_experimental_completer = 1

    au FileType rust nmap gd <Plug>(rust-def)
    au FileType rust nmap gs <Plug>(rust-def-split)
    au FileType rust nmap gx <Plug>(rust-def-vertical)
    au FileType rust nmap <leader>gd <Plug>(rust-doc)
'''