normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

Microsoft Azure PowerShell で Windows Server の最新 ImangeName を取得する方法

今回は簡単に備忘録だけ記載するが、もっといい方法があれば突っ込みを期待する。Microsoft Azure の IaaS を利用する際、作成する仮想マシンインスタンスのイメージ名を選択するため、Get-AzureVMImage のコマンドを叩く人がいるだろう。

PS C:\temp> Get-AzureVMImage
ImageName            : 03f55de797f546a1b29d1b8d66be687a__Team-Foundation-Server-2013-Update4-WS2012R2
OS                   : Windows
MediaLink            : 
LogicalSizeInGB      : 128
AffinityGroup        : 
Category             : Public
Location             : East Asia;Southeast Asia;Australia East;Australia Southeast;Brazil South;North Europe;West Europe;Japan East;Japan West;Central US;East US;East US 2;North Central US;South Central US;West US
Label                : Team Foundation Server 2013 Update 4 on Windows Server 2012 R2
Description          : Microsoft Team Foundation Server 2013 Trial on Windows Server 2012 R2 Update. Virtual Machines created with this trial image will require a product key for Team Foundation Server (such as from an 
                       MSDN Subscription). This image includes a complete installation of Team Foundation Server 2013 Update 4. Some components require additional setup and configuration. You can configure SQL Server us
                       ing SQL Server Express included in this image, by downloading and installing SQL Server Standard edition (from an MSDN Subscription), or by connect to a pre-existing SQL Server. Minimum virtual ma
                       chine size for this image is Medium. For more details on TFS server setup please see the [Team Foundation Server install guide|http://msdn.microsoft.com/en-us/library/dd631902.aspx].
Eula                 : http://www.microsoft.com/en-us/download/details.aspx?id=13350
ImageFamily          : Team Foundation Server 2013 Update 4 on Windows Server 2012 R2
PublishedDate        : 2014/11/12 17:00:00
IsPremium            : False
IconUri              : VisualStudio2013_45.png
SmallIconUri         : VisualStudio2013_45.png
PrivacyUri           : http://go.microsoft.com/fwlink/?LinkID=286720
RecommendedVMSize    : Medium
PublisherName        : Microsoft Visual Studio Group
IOType               : Standard_LRS
OperationDescription : Get-AzureVMImage
OperationId          : e2084b70-8858-3951-89f3-dfe2b1334a11
OperationStatus      : Succeeded

ImageName            : 03f55de797f546a1b29d1b8d66be687a__Visual-Studio-2013-Community-12.0.31101.0-AzureSDK-2.5-WS2012R2
OS                   : Windows
MediaLink            : 
LogicalSizeInGB      : 128
AffinityGroup        : 
Category             : Public
Location             : East Asia;Southeast Asia;Australia East;Australia Southeast;Brazil South;North Europe;West Europe;Japan East;Japan West;Central US;East US;East US 2;North Central US;South Central US;West US
Label                : Visual Studio Community 2013 on Windows Server 2012 R2
Description          : The Visual Studio Community 2013 image enables you to unleash the full power of Visual Studio to develop cross-platform solutions. Create apps in one unified IDE, and incorporate new languages, fe
                       atures, and development tools into them with Visual Studio Extensions (available in the Visual Studio Gallery).
Eula                 : http://go.microsoft.com/fwlink/?LinkId=430755
ImageFamily          : Visual Studio Community 2013 on Windows Server 2012 R2
PublishedDate        : 2014/11/12 17:00:00
IsPremium            : False
IconUri              : VisualStudio2013_45.png
SmallIconUri         : VisualStudio2013_45.png



<中略>

だが、Get-AzureVMImageの実行結果は上記の様に膨大な出力結果になる。知っている人なら何の問題もないと思うが、今回は最新の Windows Server 2012 R2(他のイメージでも良いが)のイメージ名を取得するための方法を記載する。

結論から言うと大体こんな感じ。イメージ一覧を取ってきて、イメージ名でフィルタして、更新日付でソートして最初のイメージを持ってくる。

PS C:\temp> Get-AzureVMImage | Where-Object {$_.label -like “Windows Server 2012 R2*”} | Sort-Object -Descending PublishedDate | Select-Object -Index 0

ImageName            : a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201411.01-en.us-127GB.vhd
OS                   : Windows
MediaLink            : 
LogicalSizeInGB      : 128
AffinityGroup        : 
Category             : Public
Location             : East Asia;Southeast Asia;Australia East;Australia Southeast;Brazil South;North Europe;West Europe;Japan East;Japan West;Central US;East US;East US 2;North Central US;Sou
                       th Central US;West US
Label                : Windows Server 2012 R2 Datacenter, November 2014
Description          : At the heart of the Microsoft Cloud OS vision, Windows Server 2012 R2 brings Microsoft's experience delivering global-scale cloud services into your infrastructure. It o
                       ffers enterprise-class performance, flexibility for your applications and excellent economics for your datacenter and hybrid cloud environment. This image includes Windo
                       ws Server 2012 R2 Update.
Eula                 : 
ImageFamily          : Windows Server 2012 R2 Datacenter
PublishedDate        : 2014/11/14 17:00:00
IsPremium            : False
IconUri              : WindowsServer2012R2_45.png
SmallIconUri         : WindowsServer2012R2_45.png
PrivacyUri           : 
RecommendedVMSize    : 
PublisherName        : Microsoft Windows Server Group
IOType               : Standard_LRS
OperationDescription : Get-AzureVMImage
OperationId          : 23e313f9-87f5-3457-bc5a-ca5946801382
OperationStatus      : Succeeded

仮想マシンの作成までやってみる

上記のスクリプトを利用して仮想マシンインスタンスを作成するまでのスクリプト

# 変数全般
$cloudServiceName = 'eastasia-dmz01'
$vnetName = 'vnet01'
$imageFilterName = 'Windows Server 2012 R2*'
$instanceName = 'WebVM'
$instanceSize = 'Small'
$location = 'East Asia'
$staticIP = '10.0.0.10'
$subnetName = 'Subnet-DMZ'

# 最新版の Windows Server 2012 R2 のイメージ名を取得する
$image = Get-AzureVMImage -Verbose:$false | Where-Object {$_.label -like $imageFilterName } | Sort-Object -Descending PublishedDate | Select-Object -Index 0

# 必要な場合、利用するストレージサービスを設定
# Set-AzureSubscription -CurrentStorageAccountName "<ストレージサービス名>" -SubscriptionName "<サブスクリプション名>"

# 仮想マシン・インスタンスのプロビジョニング
$vm = New-AzureVMConfig -Name $instanceName -InstanceSize $instanceSize -ImageName $image.ImageName
Add-AzureProvisioningConfig -VM $vm -Windows -AdminUsername "<ユーザ名>" -Password "<パスワード>"

# サブネットの設定
Set-AzureSubnet -SubnetNames $subnetName -VM $vm

# 静的IPの割り振り
Set-AzureStaticVNetIP -IPAddress $staticIP -VM $vm

# 仮想マシン・インスタンスを入れるクラウドサービスを作成する
New-AzureService -ServiceName $cloudServiceName -Location $location

# 仮想マシン・インスタンスの作成
New-AzureVM -ServiceName $cloudServiceName -VNetName $vnetName -VM $vm

久しぶりに GlassFish v8.0.1 を弄ったらはまったこと

JavaEE7 が出てからしばらく、情報キャッチアップのために NetBeans を弄ったときにエラーをもらった。特に NetBeansJUnit を利用した場合のエラーがちょっとわかりにくかったので、備忘録代わりに記載しておく。

NetBeansJUnit 利用時に EJB が見つからない

JUnit を実行時、以下のエラーが発生した。

 If the jar file contains valid EJBs which are annotated with EJB component level annotations (@Stateless, @Stateful, @MessageDriven, @Singleton), please check server.log to see whether the annotations were processed properly.

もろもろ調べてみたところ、どうも NetBeans のバグらしい。Issue 11296 ejb_container New - ejb container problem の記事に記載があったのが、元となる情報が削除されていた。NetBeansJUnit 実行時にデバッグモードで実行すれば急場はしのげる。

NetBeansJUnit 利用時にデータベースに接続できない

NetBeans 側で作成したデータソースに JUnit のテストコードで接続しようとしたところ、以下のエラーが発生した。

重大: Exception while invoking class org.glassfish.persistence.jpa.JPADeployer prepare method
java.lang.RuntimeException: Invalid resource : mysample__pm
	at com.sun.enterprise.connectors.ConnectorRuntime.lookupDataSourceInDAS(ConnectorRuntime.java:593)
	at com.sun.enterprise.connectors.ConnectorRuntime.lookupPMResource(ConnectorRuntime.java:517)
	at org.glassfish.persistence.common.PersistenceHelper.lookupPMResource(PersistenceHelper.java:63)
	at org.glassfish.persistence.jpa.ProviderContainerContractInfoBase.lookupDataSource(ProviderContainerContractInfoBase.java:71)
	at org.glassfish.persistence.jpa.PersistenceUnitInfoImpl.<init>(PersistenceUnitInfoImpl.java:108)
	at org.glassfish.persistence.jpa.PersistenceUnitLoader.loadPU(PersistenceUnitLoader.java:142)
	at org.glassfish.persistence.jpa.PersistenceUnitLoader.<init>(PersistenceUnitLoader.java:107)
	at org.glassfish.persistence.jpa.JPADeployer$1.visitPUD(JPADeployer.java:223)
	at org.glassfish.persistence.jpa.JPADeployer$PersistenceUnitDescriptorIterator.iteratePUDs(JPADeployer.java:510)
	at org.glassfish.persistence.jpa.JPADeployer.createEMFs(JPADeployer.java:230)
	at org.glassfish.persistence.jpa.JPADeployer.prepare(JPADeployer.java:168)
	at com.sun.enterprise.v3.server.ApplicationLifecycle.prepareModule(ApplicationLifecycle.java:925)
	at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:434)
	at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219)
	at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:539)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:535)
	at java.security.AccessController.doPrivileged(Native Method)
	at javax.security.auth.Subject.doAs(Subject.java:360)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:534)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:565)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:557)
	at java.security.AccessController.doPrivileged(Native Method)
	at javax.security.auth.Subject.doAs(Subject.java:360)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:556)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1464)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:109)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1846)
	at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1722)
	at com.sun.enterprise.admin.cli.embeddable.DeployerImpl.deploy(DeployerImpl.java:133)
	at com.sun.enterprise.admin.cli.embeddable.DeployerImpl.deploy(DeployerImpl.java:109)
	at org.glassfish.ejb.embedded.EJBContainerImpl.deploy(EJBContainerImpl.java:138)
	at org.glassfish.ejb.embedded.EJBContainerProviderImpl.createEJBContainer(EJBContainerProviderImpl.java:134)
	at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:127)
	at javax.ejb.embeddable.EJBContainer.createEJBContainer(EJBContainer.java:102)
	at todo.domain.service.todo.TodoServiceTest.setUp(TodoServiceTest.java:42)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
	at junit.framework.JUnit4TestAdapter.run(JUnit4TestAdapter.java:39)
	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:532)
	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:1179)
	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:1030)
Caused by: com.sun.appserv.connectors.internal.api.ConnectorRuntimeException: Invalid resource : mysample__pm
	at org.glassfish.jdbcruntime.service.JdbcDataSource.validateResource(JdbcDataSource.java:81)
	at org.glassfish.jdbcruntime.service.JdbcDataSource.setResourceInfo(JdbcDataSource.java:62)
	at org.glassfish.jdbcruntime.JdbcRuntimeExtension.lookupDataSourceInDAS(JdbcRuntimeExtension.java:136)
	at com.sun.enterprise.connectors.ConnectorRuntime.lookupDataSourceInDAS(ConnectorRuntime.java:589)
	... 59 more

調べた結果、如何問題らしい。

netbeans - Problem to deploy war in glassfish - Stack Overflow

NetBeans プロジェクトの glassfish-resources.xml に記載された内容を GlassFish 側の設定ファイルにも追記することで問題を回避できる。

Microsoft Azure の仮想ネットワーク上に複数NICの仮想マシンを配置してみる

先日は Network Security Group を紹介させて頂いたが、今回は複数NICを持つ仮想マシンを作成して操作してみたいと思う。すでに以下の様な立派な記事が記載されているが、動かしてみないとわからないところもあるので、本記事も合わせて一読してほしい。

今回利用する Multi NIC という社畜御用達な機能は、L サイズ以上の大きさのインスタンスを利用する必要がある。参考までに、インスタンスサイズによる NIC 登録数は以下になる。

インスタンスサイズ 作成可能NIC
L サイズ (A3) および A6 2
XL サイズ (A4) および A7 4
A9 2
D3 2
D4 4
D13 4

Multi NIC、仮想ネットワーク、Network Security Group を利用して構築するネットワークは以下になる。
f:id:waritohutsu:20141119151907p:plain

Multi NIC 仮想マシンの作成

早速 PowerShell を利用して環境を構築する。仮想ネットワーク、Network Security Group の作成は Microsoft AzureのNetwork Security Groupを使ってなんちゃってネットワーク設計(インスタンスのインターネットアクセス禁止とか)をする の記事を参考にして作成したうえで、以下の PowerShell コマンドを実行する。

# 仮想マシンイメージの選択(参考記事が使っていた Windows Serve 2012 R2 を選択
$image = Get-AzureVMImage -ImageName "a699494373c04fc0bc8f2bb1389d6106__Windows-Server-2012-R2-201408.01-en.us-127GB.vhd"

# インスタンスの大きさは Large を選択(Large 以上のサイズでないと、Multi NIC インスタンスを作成できない
$vm = New-AzureVMConfig -Name "MultiNicVM" -InstanceSize "Large" -Image $image.ImageName

# インスタンスのプロビジョニング情報を設定する
Add-AzureProvisioningConfig -VM $vm -Windows -AdminUsername <ユーザ名> -Password <パスワード>

# NIC0?は Subnet-DMZ に所属させる
Set-AzureSubnet -SubnetNames "Subnet-DMZ" -VM $vm
Set-AzureStaticVNetIP -IPAddress 10.0.0.11 -VM $vm

# NIC1 は Subnet-AP_DB に所属させる
Add-AzureNetworkInterfaceConfig -Name "NIC1" -SubnetName "Subnet-AP_DB" -VM $vm -StaticVNetIPAddress "10.0.1.11"

# 仮想ネットワーク vnet01 を指定し、仮想マシンを作成する
New-AzureVM -ServiceName <service name> -VNetName "vnet01" -VMs $vm

上記のコマンドを実行した仮想マシンリモートデスクトップで入り、ipconfig, route print を実行した結果は以下となる。

C:\Users\myuser>ipconfig

Windows IP Configuration


Ethernet adapter Ethernet 2:

   Connection-specific DNS Suffix  . : multiniceastjpvm.l5.internal.cloudapp.net

   Link-local IPv6 Address . . . . . : fe80::f479:f0e8:eac3:67ea%26
   IPv4 Address. . . . . . . . . . . : 10.0.0.11
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 10.0.0.1

Ethernet adapter Ethernet :

   Connection-specific DNS Suffix  . : multiniceastjpvm.l5.internal.cloudapp.net

   Link-local IPv6 Address . . . . . : fe80::a5f1:fd46:f60c:e6b7%22
   IPv4 Address. . . . . . . . . . . : 10.0.1.11
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 10.0.1.1

Tunnel adapter isatap.multiniceastjpvm.l5.internal.cloudapp.net:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . : multiniceastjpvm.l5.internal.cloudapp.net


Tunnel adapter Teredo Tunneling Pseudo-Interface:

   Connection-specific DNS Suffix  . :
   IPv6 Address. . . . . . . . . . . : 2001:0:9d38:90d7:2cc6:18f8:f5ff:fff4
   Link-local IPv6 Address . . . . . : fe80::2cc6:18f8:f5ff:fff4%15
   Default Gateway . . . . . . . . . : ::


C:\Users\myuser>route print
===========================================================================
Interface List
 31...00 0d 3a 50 05 96 ......Microsoft Hyper-V Network Adapter #8
 27...00 0d 3a 50 04 a9 ......Microsoft Hyper-V Network Adapter #7
  1...........................Software Loopback Interface 1
 15...00 00 00 00 00 00 00 e0 Teredo Tunneling Pseudo-Interface
 18...00 00 00 00 00 00 00 e0 Microsoft ISATAP Adapter #2
===========================================================================

IPv4 Route Table
===========================================================================
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0          0.0.0.0         10.0.0.1        10.0.0.11      5
          0.0.0.0          0.0.0.0         10.0.1.1        10.0.1.11      5
         10.0.0.0    255.255.255.0         On-link         10.0.0.11    261
        10.0.0.11  255.255.255.255         On-link         10.0.0.11    261
       10.0.0.255  255.255.255.255         On-link         10.0.0.11    261
         10.0.1.0    255.255.255.0         On-link         10.0.1.11    261
        10.0.1.11  255.255.255.255         On-link         10.0.1.11    261
       10.0.1.255  255.255.255.255         On-link         10.0.1.11    261
        127.0.0.0        255.0.0.0         On-link         127.0.0.1    306
        127.0.0.1  255.255.255.255         On-link         127.0.0.1    306
  127.255.255.255  255.255.255.255         On-link         127.0.0.1    306
        224.0.0.0        240.0.0.0         On-link         127.0.0.1    306
        224.0.0.0        240.0.0.0         On-link         10.0.0.11    261
        224.0.0.0        240.0.0.0         On-link         10.0.1.11    261
  255.255.255.255  255.255.255.255         On-link         127.0.0.1    306
  255.255.255.255  255.255.255.255         On-link         10.0.0.11    261
  255.255.255.255  255.255.255.255         On-link         10.0.1.11    261
===========================================================================
Persistent Routes:
  None

IPv6 Route Table
===========================================================================
Active Routes:
 If Metric Network Destination      Gateway
 15    306 ::/0                     On-link
  1    306 ::1/128                  On-link
 15    306 2001::/32                On-link
 15    306 2001:0:9d38:90d7:444:c23:f5ff:fff4/128
                                    On-link
 27    261 fe80::/64                On-link
 31    261 fe80::/64                On-link
 15    306 fe80::/64                On-link
 15    306 fe80::444:c23:f5ff:fff4/128
                                    On-link
 27    261 fe80::6c59:b544:5e61:1eaa/128
                                    On-link
 31    261 fe80::c480:65b1:30bd:2f52/128
                                    On-link
  1    306 ff00::/8                 On-link
 27    261 ff00::/8                 On-link
 31    261 ff00::/8                 On-link
 15    306 ff00::/8                 On-link
===========================================================================
Persistent Routes:
  None

上記を確認すると、Add-AzureNetworkInterfaceConfig で追加した NIC 側(10.0.1.11)と Set-AzureStaticVNetIP で登録された NIC ではメトリックの差がないことが分かる。
Network Security Group の NSG01, NSG02 ではそれぞれ仮想マシン⇒インターネットへのアクセスを禁止しているが、仮想マシンからインターネットに接続するにつなげたり繋げなかったりするという現象が起きた。これから、「追加した NIC には Network Security Group が効かない」ということが推察(確認レベルにはならない…)できる。
まだドキュメントが多い機能ではないので推察の域をできないところもあるが参考になれば幸いだ。

その他の留意点

また、Multi NIC 利用時の留意点としては以下となるので、利用前に一読してほしい。

  • Multi NIC は GA リリース(一般提供)なので、SIerも安心して使えるよ!(サポート上はね!!
  • NIC 追加による仮想マシンへの追加料金は存在しません
  • Linux でも Multi NIC は使えます
  • Multi-NIC仮想マシンはコマンド経由でしか作成できない(管理ポータルからは作成できない
  • 仮想マシンの作成後、NICの追加や削除はできない
  • 追加 NIC は負荷分散セット内で使用できない( ロードバランサ側のVIPとマッピング取れるのがデフォルトNICだけらしい
  • デフォルトNIC以外では Network Security Group や Force Tunneling が使えないので要注意
  • Multi NIC 利用時、オーダーはランダムになるらしい。以下は抜粋となるが、デフォルト NIC がどれになるかもどうもランダムっぽいような…。
The order of the NICs inside the VM will be random, but the IP addresses and the corresponding MACs will remain the same.

Microsoft AzureのNetwork Security Groupを使ってなんちゃってネットワーク設計(インスタンスのインターネットアクセス禁止とか)をする

御大ブログにて以下の新機能リリースがあった。

上記の機能のうち、Network Security Groupと呼ばれる機能の提供により、仮想ネットワーク上で簡易なネットワーク設計が可能となった。以下の様な社蓄心をくすぐる要件にこたえることが可能なナイス機能となっているので、今回はNetwork Security Groupの機能について紹介する。

Network Security Group の概要

MSDN - About Network Security Groups に概要がある。Network Security Group は仮想ネットワーク上に設定された サブネット or 仮想マシン、またはサブネットと仮想マシン両方に通信制御を可能とする機能だ。
IP アドレス、ポート、TCP/UDP プロトコルを指定して通信制御を行うため、冒頭で記載したインターネットへのアクセス禁止やインスタンス間(またはサブネット間)における通信制御が可能となる。
Network Security Group で利用可能なコマンドは以下となるため、詳細は MSDN を確認してほしい。

PS C:\Temp> Get-Command *NetworkSecurity*

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Cmdlet          Get-AzureNetworkSecurityGroup                      Azure
Cmdlet          Get-AzureNetworkSecurityGroupConfig                Azure
Cmdlet          Get-AzureNetworkSecurityGroupForSubnet             Azure
Cmdlet          New-AzureNetworkSecurityGroup                      Azure
Cmdlet          Remove-AzureNetworkSecurityGroup                   Azure
Cmdlet          Remove-AzureNetworkSecurityGroupConfig             Azure
Cmdlet          Remove-AzureNetworkSecurityGroupFromSubnet         Azure
Cmdlet          Remove-AzureNetworkSecurityRule                    Azure
Cmdlet          Set-AzureNetworkSecurityGroupConfig                Azure
Cmdlet          Set-AzureNetworkSecurityGroupToSubnet              Azure
Cmdlet          Set-AzureNetworkSecurityRule                       Azure

また、Network Security Groupの主な制限は以下になるので、実際に利用する際には参考にして欲しい。

  • 一つのサブスクリプションに100個までNetwork Security Groupを作成できる
  • 一つのNetwork Security Groupにつき、ルールは 200個まで設定可能
  • ACL とは併用できない(Network Security Group利用時に、あらかじめ削除しておく必要がある)
  • Multi NIC を利用している場合、デフォルト NIC にしか適用されない
  • VM 単位、Subnet 単位、または両方に適用可能

試しにネットワークを設定してみる

以下のネットワークを設定してみる。
f:id:waritohutsu:20141115163958p:plain

また、あらかじめ以下の仮想ネットワーク、インスタンスが作成済みとする。

DMZ 向けの Network Security Group を適用する

以下の PowerShell スクリプトを実行する。

# DMZ用のNetwork Security Group作成
New-AzureNetworkSecurityGroup -Name "NSG01" -Label "for vnet01 DMZ NSG" -Location "Japan East"

# インターネットからの HTTP アクセスを許可
Get-AzureNetworkSecurityGroup -Name NSG01 | Set-AzureNetworkSecurityRule -Name "AllowWEBFromInternet" -Type Inbound -Priority 100 -Action Allow -SourceAddressPrefix INTERNET -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 80 -Protocol *

# インターネットからの RDP を許可
Get-AzureNetworkSecurityGroup -Name NSG01 | Set-AzureNetworkSecurityRule -Name "AllowRDPFromInternet" -Type Inbound -Priority 500 -Action Allow -SourceAddressPrefix INTERNET -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 3389 -Protocol *

# インターネットへのアクセスを禁止
Get-AzureNetworkSecurityGroup -Name NSG01 | Set-AzureNetworkSecurityRule -Name "DenyToInternet" -Type Outbound -Priority 1100 -Action Deny -SourceAddressPrefix VIRTUAL_NETWORK -SourcePortRange * -DestinationAddressPrefix INTERNET -DestinationPortRange * -Protocol *

# NSG01 の情報を表示(なくても勝手に表示されますが、一応
Get-AzureNetworkSecurityGroup -Name NSG01 -Detailed

# Subnet-DMZ へのNetwork Security Groupの適用
Get-AzureNetworkSecurityGroup NSG01 | Set-AzureNetworkSecurityGroupToSubnet -SubnetName Subnet-DMZ -VirtualNetworkName vnet01

# Subnet-DMZ へのNetwork Security Groupへの適用の確認
Get-AzureNetworkSecurityGroupForSubnet -SubnetName Subnet-DMZ -VirtualNetworkName vnet01 -Detailed

以下の実行結果が出力されるはずだ。

Name  : NSG01
Rules :

           Type: Inbound

        Name                 Priority  Action   Source Address  Source Port R Destination Addr Destination Po Protocol
                                                Prefix          ange          ess Prefix       rt Range
        ----                 --------  ------   --------------- ------------- ---------------- -------------- --------
        AllowWEBFromInternet 100       Allow    INTERNET        *             *                80             *
        AllowRDPFromInternet 500       Allow    INTERNET        *             *                3389           *
        ALLOW VNET INBOUND   65000     Allow    VIRTUAL_NETWORK *             VIRTUAL_NETWORK  *              *
        ALLOW AZURE LOAD BAL 65001     Allow    AZURE_LOADBALAN *             *                *              *
        ANCER INBOUND                           CER
        DENY ALL INBOUND     65500     Deny     *               *             *                *              *


           Type: Outbound

        Name                 Priority  Action   Source Address  Source Port R Destination Addr Destination Po Protocol
                                                Prefix          ange          ess Prefix       rt Range
        ----                 --------  ------   --------------- ------------- ---------------- -------------- --------
        DenyToInternet       1100      Deny     VIRTUAL_NETWORK *             INTERNET         *              *
        ALLOW VNET OUTBOUND  65000     Allow    VIRTUAL_NETWORK *             VIRTUAL_NETWORK  *              *
        ALLOW INTERNET OUTBO 65001     Allow    *               *             INTERNET         *              *
        UND
        DENY ALL OUTBOUND    65500     Deny     *               *             *                *              *
AP/DB 向けの Network Security Group を適用する

以下の PowerShell スクリプトを実行する。

# APサーバ、DBサーバ用のセキュリティグループ作成
New-AzureNetworkSecurityGroup -Name "NSG02" -Label "for vnet01 AP_DB NSG" -Location "Japan East"

# インターネットからの HTTP アクセスを許可
Get-AzureNetworkSecurityGroup -Name NSG02 | Set-AzureNetworkSecurityRule -Name "AllowWEBFromInternet" -Type Inbound -Priority 100 -Action Allow -SourceAddressPrefix INTERNET -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 80 -Protocol *

# インターネットからの RDP を許可
Get-AzureNetworkSecurityGroup -Name NSG02 | Set-AzureNetworkSecurityRule -Name "AllowRDPFromInternet" -Type Inbound -Priority 500 -Action Allow -SourceAddressPrefix INTERNET -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 3389 -Protocol *

# インターネットへのアクセスを禁止
Get-AzureNetworkSecurityGroup -Name NSG02 | Set-AzureNetworkSecurityRule -Name "DenyToInternet" -Type Outbound -Priority 1100 -Action Deny -SourceAddressPrefix VIRTUAL_NETWORK -SourcePortRange * -DestinationAddressPrefix INTERNET -DestinationPortRange * -Protocol *

# DMZ Subnet(NSG01) へのアクセスを禁止
Get-AzureNetworkSecurityGroup -Name NSG02 | Set-AzureNetworkSecurityRule -Name "DenyToNSG01" -Type Outbound -Priority 2000 -Action Deny -SourceAddressPrefix 10.0.1.0/24 -SourcePortRange * -DestinationAddressPrefix 10.0.0.0/24 -DestinationPortRange * -Protocol *

# DMZ Subnet(NSG01) からのアクセスを許可
Get-AzureNetworkSecurityGroup -Name NSG02 | Set-AzureNetworkSecurityRule -Name "AllowFromNSG01" -Type Inbound -Priority 2100 -Action Allow -SourceAddressPrefix 10.0.0.0/24 -SourcePortRange * -DestinationAddressPrefix 10.0.1.0/24 -DestinationPortRange * -Protocol *

# Subnet-AP_DB へのNetwork Security Groupの適用
Get-AzureNetworkSecurityGroup NSG02 | Set-AzureNetworkSecurityGroupToSubnet -SubnetName Subnet-AP_DB -VirtualNetworkName vnet01

# Subnet-AP_DB へのNetwork Security Groupへの適用の確認
Get-AzureNetworkSecurityGroupForSubnet -SubnetName Subnet-AP_DB -VirtualNetworkName vnet01 -Detailed

以下の実行結果が出力されるはずだ。

Name  : NSG02
Rules :

           Type: Inbound

        Name                 Priority  Action   Source Address  Source Port R Destination Addr Destination Po Protocol
                                                Prefix          ange          ess Prefix       rt Range
        ----                 --------  ------   --------------- ------------- ---------------- -------------- --------
        AllowWEBFromInternet 100       Allow    INTERNET        *             *                80             *
        AllowRDPFromInternet 500       Allow    INTERNET        *             *                3389           *
        AllowFromNSG01       2100      Allow    10.0.0.0/24     *             10.0.1.0/24      *              *
        ALLOW VNET INBOUND   65000     Allow    VIRTUAL_NETWORK *             VIRTUAL_NETWORK  *              *
        ALLOW AZURE LOAD BAL 65001     Allow    AZURE_LOADBALAN *             *                *              *
        ANCER INBOUND                           CER
        DENY ALL INBOUND     65500     Deny     *               *             *                *              *


           Type: Outbound

        Name                 Priority  Action   Source Address  Source Port R Destination Addr Destination Po Protocol
                                                Prefix          ange          ess Prefix       rt Range
        ----                 --------  ------   --------------- ------------- ---------------- -------------- --------
        DenyToInternet       1100      Deny     VIRTUAL_NETWORK *             INTERNET         *              *
        DenyToNSG01          2000      Deny     10.0.1.0/24     *             10.0.0.0/24      *              *
        ALLOW VNET OUTBOUND  65000     Allow    VIRTUAL_NETWORK *             VIRTUAL_NETWORK  *              *
        ALLOW INTERNET OUTBO 65001     Allow    *               *             INTERNET         *              *
        UND
        DENY ALL OUTBOUND    65500     Deny     *               *             *                *              *

しかして

上記で設定は完了だが、設定がうまく反映されたり反映が遅れたりする場合があるようだ。MSDN にも以下の記載があり、反映に数分はかかることが記載されているが、体感で30分以上の時間が過ぎたにも関わらず設定が反映されていない場合もあった(逆に、ルールを変更したら即座に反映された場合もあった)ので、利用時には注意してほしい。

Associating an NSG to a VM - When a NSG is directly associated to a VM, the Network access rules in the NSG are directly applied to all traffic that is destined to the VM. Whenever the NSG is updated for rule changes, the changes are reflected in the traffic handling within minutes. When the NSG is dis-associated from the VM, the state goes back to whatever it was before the NSG, i.e. the system defaults before the introduction if NSG will be used.
Associating an NSG to a Subnet - When a NSG is associated to a subnet, the Network access rules in the NSG are applied to all the VMs in the subnet. Whenever the access rules in the NSG are updated the changes are applied to all Virtual machines in the subnet within minutes.

Exchange Web Services Managed API SDK を使ってみた

前回のエントリで試した PowerShell を利用した CUI での Exchange Server への疎通はうまくいかなかった。今回は Exchange Web Services Managed API SDK の利用を検討してみた。
Exchange Web Services Managed API SDKExchange Server 2007 SP1 以降で利用可能であり、開発者側で理解しやすい API を用いて Exchange Server 側の情報を容易に操作することができる。
以下の様の NuGET で取得が可能であるため、簡単に取得することができる。今回はこちらを利用してオンプレ向けの Exchange Server に疎通を取ってみる。

上記の通り、32bit 版と 64bit 版があるので留意が必要だ。

Exchange Web Services Managed API SDK を利用した疎通を実施

Exchange Web Services Managed API SDK は NuGet 経由で取得できるため、以下の画面を参考に「Exchange」の文字列で検索して Exchange Web Services Managed API SDK を取得してほしい。
f:id:waritohutsu:20140504161809p:plain

Exchange Web Services Managed API SDK のインストール後、以下のコードを記載して Exchange Server から予定を取得する。

using System;
using System.Linq;
using Microsoft.Exchange.WebServices.Data;

namespace ExchangeConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // エンプラ向けに古いバージョンの Exchange Server を指定だが、用途に合わせてオプション指定
            ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);

            // EWS のレスポンス情報をログに出力
            service.TraceEnabled = true;
            service.TraceFlags = TraceFlags.All;

            // 環境によっては Autodiscover が無理だが、以下に Autodiscover を推奨する記載がある
            // http://msdn.microsoft.com/en-us/library/dn467891(v=exchg.150).aspx
            // service.AutodiscoverUrl("<ユーザ名>@<ドメイン>", RedirectionUrlValidationCallback);

            // Autodiscover を設定せず、直接 URI を指定する
            service.Url = new Uri(@"https://<Exchange Server アドレス>/EWS/Exchange.asmx");
            service.Credentials = new WebCredentials("<ユーザ名>@<ドメイン>", "<パスワード>");

            // 現在からひと月前~ひと月後を指定して予定を取得する
            var folder = CalendarFolder.Bind(service, WellKnownFolderName.Calendar);
            DateTime dtStart = DateTime.Today;
            dtStart = dtStart.AddMonths(-1);
            DateTime dtEnd = dtStart.AddMonths(1);
            var view = new CalendarView(dtStart, dtEnd);
            foreach (var appointment in folder.FindAppointments(view))
            {
                Console.WriteLine("---------------------");
                Console.WriteLine("Subject = {0}", appointment.Subject);
                Console.WriteLine("Start = {0}", appointment.Start);
                Console.WriteLine("End = {0}", appointment.End);
                Console.WriteLine("IsAllDayEvent = {0}", appointment.IsAllDayEvent);
                Console.WriteLine("IsReminderSet = {0}", appointment.IsReminderSet);
                if (appointment.IsReminderSet == true)
                {
                    // appointment.IsReminderSet == true の状態で参照しないとエラーが出る
                    Console.WriteLine("ReminderDueBy = {0}", appointment.ReminderDueBy);
                }
            }

            Console.WriteLine("!!!!!!!!! end !!!!!!");
            Console.ReadLine();
        }
    }
}

上記のコードにおける「service.TraceEnabled = true; service.TraceFlags = TraceFlags.All;」の指定により、以下のように Exchange Server とのやり取りがログとして出力される。
f:id:waritohutsu:20140504201755p:plain

さらに、標準出力には以下が出力され、無事に Exchange Server から予定が取得されていることが確認できる。
f:id:waritohutsu:20140504201618p:plain

2007以前の Exchange Server から予定をひっこ抜こうとした件

所用で 2007 以前の Exchange Server から予定をひっこ抜こうとしたのだが、疎通の時点で色々と問題があってうまくいかなかった。備忘録としてやったことを簡単にまとめておく。

実施した内容

まずは基本中の基本である以下 TechNet 記事を参照した。

上記は Exchange Online が適用先となっているが、一応オンプレの Exchange Server で出来るかためしたところ以下のエラーが出た。

SSL 証明書の失効チェックできませんでした。取り消しを確認するために使用するサーバーがアクセスできない可能性があります。

調べてみたところ、Windows 専用の Office 365 でのリモート PowerShell を使用して接続するときに、「SSL 証明書をチェックできませんでしたの失効」エラー に記載がある通り、オンプレ Exchange Server の様にインターネットアクセスを持たないために証明書の失効がチェックができない場合に発生するらしい。

次に、上記のオプションを考慮して以下の PowerShell コマンドを実行した。

# Exchange Server ログイン用の認証情報取得
$myCredential = Get-Credential

# オンプレ向けにインターネットへルート証明書の失効期限を聞きに行かないようにする
$sessionOption = New-PSSessionOption -SkipRevocationCheck

# オンプレ Exchange Server に接続しに行く
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://<サーバ名> -Credential $myCredential -Authentication Basic -AllowRedirection -SessionOption $sessionOption

が、以下のエラーが出てきて目頭が熱い気味。どうやら Exchange Server 側で WS-Management プロトコルを有効化する必要がある?らしい。

New-PSSession : [<サーバ名>] リモート サーバー <サーバ名> への接続に失敗し、次のエラー メッセージが返されました: WinRM クライアントは HTTP サーバーに要求を送信し、要求された HTTP URL が使用不能であるとい
う応答を受け取りました。 これは通常、WS-Management プロトコルをサポートしていない HTTP サーバーによって返されます。詳細については、about_Remote_Troubleshooting のヘルプ トピックを参照してください。
発生場所 行:1 文字:12
+ $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri ht ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [New-PSSession], PSRemotingTransportException
    + FullyQualifiedErrorId : URLNotAvailable,PSSessionOpenFailed

その他の方法は?

Exchange Server 2007 SP1 以降なら Microsoft Exchange Web Services Managed API が利用可能とのこと。以下の SDK を利用することで何とかなりそうだが、Exchange Server 2007以前では…orz

色々と操作されている情報が以下にあった。後で見よう
MS Exchangeからスケジュールを抜き出すんだぜ

Azure Automaiton を試してみる

2014年4月に開催された BUILD 2014 では様々な機能が追加されたが、ちょっとだけ触ってみた Azure Automation について記載してみる。現時点ではまだプレビュー機能なので、管理ポータルから Activate を実施する必要がある。Azure Automation の公式サイトは以下になるが、まだ情報は少ないようだ。。。

Azure Automaiton の概要

Azure Automaiton を利用することで、Microsoft Azure 上で PowerShellスクリプトを利用/組み合わせで様々な処理を実施することができる。こちらの Get started with Azure Automation にも記載されているが、Windows PowerShell Workflows としての利用ができるようだ。
後述するが、PowerShellスクリプトRunbook として登録して利用することから、どうやら System Center 2012 R2 Orchestrator の Microsoft Azure 版というのがイメージしやすそうだ*1

Get Started を試す

さっそく Get started with Azure Automation を参照しつつ試してみようと思う。
まずは Script Centor から、以下の Write-HelloWorld.ps1 をダウンロードする。

  • Write-HelloWorld.ps1
workflow Write-HelloWorld {
    param (
        [parameter(Mandatory=$false)]
        [String]$Name = "World"
    )
        Write-Output "Hello $Name"
}

次に、管理ポータルから Automation のアカウントを作成する。現在はプレビュー版であり「米国東部」しか選択できない点に注意してほしい。
f:id:waritohutsu:20140407041053j:plain

更に RUNBOOKS タブを選択し、IMPORT ボタンを押下して RUNBOOK 向けの *.ps1 ファイルを選択してアップロードする。
f:id:waritohutsu:20140407041106j:plain

IMPORT の完了後に登録した RUNBOOK を選択し、AUTHOR → DRAFT のタブを選択してスクリプトを PUBLISH する。
f:id:waritohutsu:20140407041241j:plain

PUBLISH の実施後、START を押下することで RUNBOOK が実行される。実行の結果は以下の様に確認できる。
f:id:waritohutsu:20140407041629j:plain

複数の RUNBOOK を実行する

上記で実施した Hello Worldスクリプトに続き、Script Centor のサンプルに登録された How to Invoke a Child Runbook を参照し、以下のスクリプトを作成した。こちらのスクリプトは Write-HelloWorld.ps1 を子供として呼び出すスクリプトになる。

workflow Invoke-ChildRunbookSample
{
    
    [OutputType( [object] )]
    param (
		# Variable
        [parameter(Mandatory=$true)]
        [String]$MyVariable
    )
    
    Write-HelloWorld -Name "Hello World を書いてみる"
    Write-HelloWorld -Name $MyVariable
}

上記のスクリプトを RUNBOOK として登録して PUBLISH の実施*2後、START を押下することで以下の様にログ出力されていることが確認できる。
f:id:waritohutsu:20140407041755j:plain

参考情報

*1:System Centor の OrchestratorRunbook デザイナー相当のものがまだ存在しないため、利用はハードルが高そうだ…

*2:または Asset に必ず登録する必要がある