ServicePrincipalを用いたAzure認証

# 1. やりたいこと
AzureのSQL serverに外部から接続するためには、ファイヤウォールで許可するipを設定しなければならない。クライアント側がglobal ipだったらいいのだが、今回はそうではない。ルーターの電源を切らなければ、ipは変わってないので大丈夫なのだけど、停電とかその他理由で突然ipが変更になった場合に、SQL Serverに接続できなくなる。

なので、global ipが変わったときに、ファイヤウォールの設定を自動的に行いたいというのが、やりたいこと。
そのためには、Azure認証を自動的に行う必要がある。AzureのServicePrincipalを使って、Azure認証を行い、PowershellでSQL Serverのファイヤウォールの設定を変更する。

参考：

https://www.blog.slow-fire.net/2020/05/18/azure-powershellで非対話型でログインする方法/](https://www.blog.slow-fire.net/2020/05/18/azure-powershell%E3%81%A7%E9%9D%9E%E5%AF%BE%E8%A9%B1%E5%9E%8B%E3%81%A7%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/

https://docs.microsoft.com/ja-jp/powershell/azure/create-azure-service-principal-azureps?view=azps-8.0.0&viewFallbackFrom=azps-3.8.0

# 2. Service Principalの作成
サービスプリンシパルについてはここを参照。

https://tech-lab.sios.jp/archives/23371


・Azure Active Directory > アプリの登録 > 新規登録
アプリケーションの名前を決める。ここでは、ServicePrincipalTestとする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/991ba291-0061-7625-ddaa-5b46bc8774fc.png)

・アプリケーションIDとテナントIDを後から使うので控えておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/1b55ee07-d64f-c73f-ac4e-b20882396de3.png)

・"証明書とシークレット"を追加。
新しいクライアント シークレットを選択。有効期限を決めて、追加。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/7d34c81b-e9b2-483f-fc59-1d7aefaf81ff.png)

・"値"というのが認証用のパスワードになるので、覚えておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/75532bc3-2beb-8821-57a5-4949e4dc806c.png)

# 3. カスタムロールの作成
ServicePrincipalにどのような権限を持たせるかを定義する。ロールに紐づいたActionがあって、ServicePrincipalにロールを割り当てるのだが、今回やりたいのはファイヤウォール規則の変更なので、それだけをもつロールを定義して、そのロールをServicePrincipalに割り当てる。

・サブスクリプション>アクセス制御(IAM)>カスタムロールを作成する
カスタムロール名を決める。ここでは、"SQL firewallRules”とする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/e6cca365-632c-5758-8ecb-f94b2056982f.png)

・アクセス許可の追加をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/84d47f4b-9895-6b4e-778b-a894b0a74860.png)

・今回ファイヤウォールのルール作成なので、firewallと検索窓に入れて、アクションを選択。
Microsoft.Sql/servers/firewallRulesのCreateなどにチェック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/e0cb62c0-9ae9-901a-7e96-ba76235c1802.png)

# 4. ServicePrincipalにロールを割り当てる
・サブスクリプション>アクセス制御(IAM) > 追加 >ロールの割当の追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/a19ad759-1fd8-ae21-c88e-9c21829a986d.png)

・検索窓にfirewallと打って、先ほど追加したロールを探す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/7333df1d-aa4b-31ef-34de-97dbcedab204.png)

・“メンバーを選択する”。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/ac589a8d-f7f4-121f-1701-f4a426d2b7ba.png)

・"選択"で、さきほど作成したServicePrincipalの名前を入れると、下にでてくるので、選択して"選択"ボタンを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/0f0fac77-fbcd-6e8b-c83a-83e6a2e71732.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252335/235e94c8-1fd9-95ed-ae7b-22ab88f655d5.png)

# 5. Azure PowerShellをインストール
ログインを行うPCにAzure PowerShellを入れる。

```powershell
# PowerShellGetの更新
# PowerShellを管理者として起動する。アイコンを右クリックして管理者として実行するを行う。
Install-Module PowerShellGet -Force

# ポリシーの変更
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

# Azure PowerShellのインストール
Install-Module -Name Az -AllowClobber -Scope CurrentUser
```

```powershell
#Import-Module Az.Resources
$tenantId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$applicationId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$passwd = ConvertTo-SecureString "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -AsPlainText -Force
$pscredential = New-Object System.Management.Automation.PSCredential($applicationId, $passwd)
Connect-AzAccount -ServicePrincipal -Credential $pscredential -Tenant $tenantId
Read-Host "続けるには Enter キーを押してください..."
```
tenantIdはテナントID、applicationIdはアプリケーションID、passwdは、ServicePrincipalを作ったときに出てきた"値"を入れる。このスクリプトを走らせれば、Azureにログインができる。それから、ログインしたあとにファイヤーウォールの設定をする。

# 6. ファイヤウォールの設定

```powershell
$ipaddress = (Invoke-WebRequest inet-ip.info/ip -UseBasicParsing).Content
Write-Host "Global IP: "  $ipaddress

New-AzSqlServerFirewallRule -ResourceGroupName "xxxxxxxxxx" -ServerName "xxxxxxxxx"
-FirewallRuleName xxxxxxxxxx -StartIpAddress $ipaddress -EndIpAddress $ipaddress
Read-Host "続けるには Enter キーを押してください..."
```
ResourceGroupName はリソースグループ、ServerNameは接続するサーバー名を入れる。
FirewallRuleNameはファイヤウォール規則の名前を適当に入れる。

実際には、このスクリプトをC#でつくったサービスで実行させている。一連のスクリプト全体を一応エンコードしている。
あと、Invoke-WebRequestで-UseBasicParsingを使わないと、サービスで実行したときにIEが設定されてないと言われてエラーになる。これで結構はまった。