ふるすたっくえんじにあの日記

ASP .NET MVC (C#)、.NET Framework、iOS (Objective-c) アプリ、Androidアプリ (Java)、AWSあたり

【AWS】固定IP用のVPNを構築する-初心者向け

はい。久しぶり。いつぶりでしょ。
PVあがりそうなタグつけておきますね。
#在宅ワーク #リモートワーク #ワーケーション #コロナ対策 #出社自粛
#SSO #AWS #AWS VPN Client #VPC

最近いくつか固定IPなVPN構築の要望あって、自社のVPNおったてつつ手順をまとめておきますよ。
初心者向けっていくつか見たけど、全然初心者向けじゃなかったよ。CIDRなんて初心者わからへんやろ。
そして自社のシステムが一番イケてるのは内緒。一番最後にやる&何の制約もなくて自由度が一番高いから当たり前っちゃ当たり前なんだけど。
そのうちIdPはKeycloakに移行予定。

  • Oktaの設定とIAM IDプロバイダーの作成

めんどくなったのでこちらを参考に
https://dev.classmethod.jp/articles/clientvpn_saml_okta/

  • 証明書作成とインポート

gitコマンドがターミナルから使える前提。
以下のコマンドをさくっと実行しましょう。

```
git clone https://github.com/OpenVPN/easy-rsa.git
cd easy-rsa/easyrsa3
./easyrsa init-pki
./easyrsa build-ca nopass
./easyrsa build-server-full vpn.static.ip.server nopass
```

https://ap-northeast-1.console.aws.amazon.com/acm/home?region=ap-northeast-1#/importwizard/
証明書本文: pki/issued/vpn.static.ip.server.crtの-----BEGIN CERTIFICATE-----から-----END CERTIFICATE-----まで
証明書のプライベートキー: pki/private/vpn.static.ip.server.key
証明書チェーン: pki/ca.crt
の内容をコピペしましょう。

  • Elastic IP取得

https://ap-northeast-1.console.aws.amazon.com/vpc/home?region=ap-northeast-1#Addresses:
ここから「Elastic IP アドレスの割り当て」
AmazonIPv4 アドレスプール」
「割り当て」
これでできたIPアドレスグローバルIPになります。

https://ap-northeast-1.console.aws.amazon.com/vpc/home?region=ap-northeast-1#wizardSelector:
ここから「パブリックとプライベートサブネットを持つ VPC」を作成
VPC名: 任意
アベイラビリティーゾーン: パブリック/プライベートで同じに
パブリック/プライベートサブネット名: 指定
Elastic IP 割り当て ID: さっき指定したやつを選択

  • クライアント VPN エンドポイントの作成

https://ap-northeast-1.console.aws.amazon.com/vpc/home?region=ap-northeast-1#CreateClientVpnEndpoint:
ここから
名前タグ: 任意
説明: 任意
クライアントIPv4 CIDR: 10.10.0.0/16
サーバー証明書 ARN: さっき作った証明書
認証オプション: ユーザーベースの認証を使用 - 統合認証
SAML プロバイダー ARN: さっき作ったやつ

  • 関連付けなどなど

作ったクライアント VPN エンドポイント - 関連付け: VPCは作ったVPC、サブネットはプライベートのほうを設定
作ったクライアント VPN エンドポイント - 承認
 アクセスを有効にする送信先ネットワーク: 0.0.0.0/0
 すべてのユーザーにアクセスを許可する
作ったクライアント VPN エンドポイント - ルートテーブル
 ルート送信先: 0.0.0.0/0
 ターゲット VPC サブネット ID: プライベートのほう

  • 設定ファイルのダウンロード

作ったクライアント VPN エンドポイントを選択して「クライアント設定のダウンロード」

  • 接続

AWS Client VPN Download | Amazon Web Services
ここからダウンロードしてインストール
開いたらファイル - プロファイルを管理 - プロファイルを追加でさっき作ったファイルを指定
で、接続

いじょ。



Github PR作成 from GAS

昔作ったけど、気に食わなかった&他社で作ったから勝手に使えないので自社用に作り直したぉ。
ごにょごにょしたらスプレッドシートから作れるね!

おもむろにこんなのを用意しましょう。
github_repos_api.gs

var GithubReposAPI = function(repositoryOwner, repository, accessToken) {
  this.repositoryOwner = repositoryOwner;
  this.repository = repository;
  this.accessToken = accessToken;
};
// PRとブランチをセットで作成
GithubReposAPI.prototype.createPullRequestWithBranch = function(sourceBranchName, newBranchName, authorName, authorEmail, title, body, draft) {
  this.createBranch(sourceBranchName, newBranchName, title, authorName, authorEmail);
  return this.createPullRequest(title, body, newBranchName, sourceBranchName, draft);
}

// ブランチ作成
GithubReposAPI.prototype.createBranch = function(sourceBranchName, newBranchName, message, authorName, authorEmail) {
  const commit = this.createCommit(sourceBranchName, message, authorName, authorEmail);
  return this.execute(
    'POST',
    '/git/refs',
    {
      'ref': 'refs/heads/' + newBranchName,
      'sha': commit.sha
    }
  );
};
GithubReposAPI.prototype.createCommit = function(branchName, message, authorName, authorEmail) {
  const branch = this.fetchBranch(branchName);
  return this.execute(
    'POST',
    '/git/commits',
    {
      'message': message,
      'author': {
        'name': authorName,
        'email': authorEmail
      },
      'parents': [
        branch.commit.sha
      ],
      'tree': branch.commit.commit.tree.sha
    });
};
GithubReposAPI.prototype.fetchBranch = function(branchName) {
  return this.execute('GET', '/branches/' + branchName);
};

// PR作成
GithubReposAPI.prototype.createPullRequest = function(title, body, head, base, draft) {
  return this.execute(
    'POST',
    '/pulls',
    {
      'title': title,
      'body': body,
      'head': head,
      'base': base,
      'draft': draft
    }
  );
};

GithubReposAPI.prototype.execute = function(method, api, payload) {
  const url = 'https://api.github.com/repos/' + this.repositoryOwner + '/' + this.repository + api;
  const param = this.generateParam(method, payload);
  return fetch(url, param);
};
GithubReposAPI.prototype.generateParam = function(method, payload) {
  if (payload) {
    return {
      'method': method,
      'Content-Type': 'application/json',
      'muteHttpExceptions': true,
      'payload': JSON.stringify(payload),
      'headers': {
        'Authorization': 'token ' + this.accessToken
      }
    };
  }
  return {
    'method': method,
    'Content-Type': 'application/json',
    'muteHttpExceptions': true,
    'headers': {
      'Authorization': 'token ' + this.accessToken
    }
  };
};

function fetch(url, param) {
  Logger.log('[Request]---------------------------\n' + url + '\n' + JSON.stringify(param));
  var ret = JSON.parse(UrlFetchApp.fetch(url, param));
  Logger.log('[Response]---------------------------\n' + JSON.stringify(ret));
  return ret;
}


使い方

const api = new GithubReposAPI(
  'arrvis', // organization or username
  'test-repository', // リポジトリ名
  'XXXXXXXX' // Personal Access Token
);
api.createPullRequestWithBranch(
  'master', // 元ブランチ
  'feature/hoge', // 新しく作るブランチ名
  'Yutaka Izumaru', // author名
  'y.izumaru@arrvis.com', // authorメアド,
  'PRタイトル',
  'PR本文',
  false // draftかどうか
);


【iOS】GoogleService-Info.plistを環境別に分ける

ひさびさに書く

devdevdev.hatenablog.com

ここらへんが終わってること前提。まぁ2018年版なんでちょっと古いんですけどね。
TARGETS→Build Settings
らへんができてればおっけかと

$PROJECT_DIR/googleとか作って以下のファイルをぶちこみましょう

  • 本番用:GoogleService-Info.plist
  • ステージング用:GoogleService-Info.staging.plist
  • 開発用:GoogleService-Info.dev.plist

TARGETS→Build PhasesでNew Run Script Phaseして以下の内容を書きましょう

cp $PROJECT_DIR/google/GoogleService-Info$ConfigurationName.plist ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist

いじょー


Mac初期設定 for フルスタックエンジニア

【2021/02/14更新済み】

  • Catalina(zsh)対応にしました。
  • 使ってるやつとかインストールするものとか最新にしました。

//------------------------------------------------------------------------------------
備忘録。
フルスタックエンジニアな僕がMacを新しく買った時にやること。
構成管理全部自動でできたらいいのに&できそうとは思うけど数年に1回だしなぁ。
秘密鍵とか設定とかはだいたいDropboxに置いてあります。

WebやらApp Storeやらからインストールするもの
・開発以外

・開発系

ターミナルでやること

# zsh
ln -s ~/Dropbox/zsh/zprofile ~/.zprofile
ln -s ~/Dropbox/zsh/zshrc ~/.zshrc

# vim
echo -e -n ':syntax on\n' >> ~/.vimrc

# ssh
ln -s ~/Dropbox/ssh ~/.ssh

# homebrew
xcode-select --install
sudo xcodebuild -license
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew doctor

# nodeenv
brew install nodenv
nodenv install X.X.X # 任意のバージョンをインストール
nodenv rehash
nodenv global X.X.X

# rbenv
brew install rbenv ruby-build
# どっちか source ~/.bash_profile / source ~/.zshrc
rbenv install $(rbenv install -l | grep -v - | tail -1)
rbenv global $(rbenv versions | grep -v - | tail -1)

# Node.js / yarn
brew install yarn

# iOS
brew install swiftlint
brew install carthage
brew tap blender/tap https://github.com/blender/homebrew-tap.git
brew install blender/homebrew-tap/rome

# AWS
brew install awscli
ln -s ~/Dropbox/aws ~/.aws

# Firebase
npm install -g firebase-tools

# VSCode
rm -rf ~/Library/Application\ Support/Code/User
mkdir -p ~/Library/Application\ Support/Code/User
ln -s ~/Dropbox/code/* ~/Library/Application\ Support/Code/User

# Xcode
defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

# VSCode
## 共通系

  • Remote Development

# Ruby(Rails)

# HTML/CSS

  • IntelliSense for CSS, SCSS class names in HTML, Slim and SCSS


Xcode10 Abort trap:6

たまには書く。

To iOSえんじにあーな皆様
Xcode10にすると以下のコードが使えなくなる模様だぉ
なんでだかわからんけど、調べる暇はないんだぉ

import UIKit

final class FooViewController: UIViewController {
    init() {
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

こっちならおっけーらしいけどさーけどさー
convenience initってinitじゃないじゃん?

import UIKit

final class FooViewController: UIViewController {
    convenience init() {
        self.init(nibName: nil, bundle: nil)
    }
}


【Cordova】 bump


プラグインとかあるけど、よくよく考えたら、fastlane使ってりゃRubyで書けばいいよね。
なお、Unity / Cocos2d-x に加え、Cordova pluginの作り方も覚えた。

  lane :bump do
    require 'rexml/document'
    doc = REXML::Document.new(File.read('../config.xml'))
    element = doc.elements['widget']
    element.attributes['android-versionCode'] = element.attributes['android-versionCode'].to_i + 1
    element.attributes['ios-CFBundleVersion'] = element.attributes['ios-CFBundleVersion'].to_i + 1
    File.write('../config.xml', doc)
  end


【WPF】KeyBinding with TriggerAction(Data Binding対応版)

はい。昨日こんなの書きました。動きませんでした。
参考記事によるとTriggerBaseはFreeazableだから、当然TriggerBaseを継承しているやつなら問題ないと思ったんですけどね。ICommandを実装してるとだめらしい。
というわけで書き直しました。

devdevdev.hatenablog.com


InputBindingTrigger

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace Hoge.Trigger
{
    public class InputBindingTrigger : TriggerBase<FrameworkElement>
    {
        public static readonly DependencyProperty InputBindingProperty =
            DependencyProperty.Register("InputBinding", typeof(InputBinding) , typeof(InputBindingTrigger) , new UIPropertyMetadata(null));

        public InputBinding InputBinding
        {
            get => (InputBinding)GetValue(InputBindingProperty);
            set => SetValue(InputBindingProperty, value);
        }

        private InputBindingCommand command = new InputBindingCommand();

        protected override void OnAttached()
        {
            if (InputBinding == null)
            {
                base.OnAttached();
                return;
            }

            InputBinding.Command = command;
            command.OnExecute += Command_OnExecute;
            if (AssociatedObject.Focusable)
                AssociatedObject.InputBindings.Add(InputBinding);
            else
            {
                FrameworkElement root = null;
                AssociatedObject.Loaded += delegate
                {
                    root = GetRootElement(AssociatedObject);
                    if (!root.InputBindings.Contains(InputBinding))
                        root.InputBindings.Add(InputBinding);
                };
                AssociatedObject.Unloaded += delegate
                {
                    root.InputBindings.Remove(InputBinding);
                };
            }
            base.OnAttached();
        }

        private FrameworkElement GetRootElement(FrameworkElement frameworkElement)
        {
            var parent = frameworkElement.Parent as FrameworkElement;
            if (parent == null)
            {
                Debug.Assert(frameworkElement.Focusable);
                frameworkElement.Focus();
                return frameworkElement;
            }
            return GetRootElement(parent);
        }

        protected override void OnDetaching()
        {
            command.OnExecute -= Command_OnExecute;
            base.OnDetaching();
        }

        private void Command_OnExecute(object parameter) => InvokeActions(parameter);
    }

    internal class InputBindingCommand : ICommand
    {
        public event EventHandler CanExecuteChanged = delegate { };

        public Action<object> OnExecute = delegate { };

        public bool CanExecute(object parameter) => true;

        public void Execute(object parameter) => OnExecute.Invoke(parameter);
    }
}

ICommandを実装するのやめただけですね。
あと、RootElement取得するように変えてるっす。ので、ちょっとxamlが変わります。
ルート要素のFocusableをTrueに。
TriggerActionはTrigger.Actionsに。
なお、TriggerActionは前回用意したやつなので省略。



<Window x:Class="Hoge.Views.MainWindow"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
                 xmlns:action="clr-namespace:Hoge.Action"
                 xmlns:trigger="clr-namespace:Hoge.Trigger"
                 Focusable="True">
    <Grid>
        <i:Interaction.Triggers>
            <trigger:InputBindingTrigger>
                <trigger:InputBindingTrigger.InputBinding>
                    <KeyBinding Modifiers="Ctrl" Key="N"/>
                </trigger:InputBindingTrigger.InputBinding>
                <trigger:InputBindingTrigger.Actions>
                    <action:ShowFolderBrowserDialogAction Description="選択せーや"
                                                                                       SelectedPath="{Binding SelectedPath.Value, Mode=OneWayToSource}" />
                </trigger:InputBindingTrigger.Actions>
            </trigger:InputBindingTrigger>
        </i:Interaction.Triggers>
    </Grid>
</Window>


参考:
qiita.com